Skip to content

Commit

Permalink
create custom MAP compoenent, env setup, and performance drawback str…
Browse files Browse the repository at this point in the history
…ick setup
  • Loading branch information
yagnik-finestar committed Apr 27, 2023
1 parent 696ebb6 commit 65dd7bf
Show file tree
Hide file tree
Showing 12 changed files with 85 additions and 106 deletions.
2 changes: 1 addition & 1 deletion .env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
declare namespace NodeJS {
interface ProcessEnv {
REACT_APP_API_KEY: string;
REACT_APP_API_URL: string;
}
}
57 changes: 30 additions & 27 deletions src/@types/Type.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { ToastContainerProps } from "react-toastify";
import { ToastProps } from "react-toastify/dist/types";
import {
HTMLButtonTypeElement,
HTMLClassNameAttribute,
HTMLIdAttribute,
HTMLInputTypeAttribute,
HTMLOnChangeAttribute,
HTMLOnClickAttribute,
HTMLOnSubmitAttribute,
ToastPosition,
HTMLButtonTypeElement,
HTMLClassNameAttribute,
HTMLIdAttribute,
HTMLInputTypeAttribute,
HTMLOnChangeAttribute,
HTMLOnClickAttribute,
HTMLOnSubmitAttribute,
ToastPosition,
} from "./UnionTypes";

/*
Expand Down Expand Up @@ -38,7 +38,7 @@ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement>
placeholder?: string | undefined;
className?: HTMLClassNameAttribute;
onChange?: HTMLOnChangeAttribute;
}
}

export interface ImgProps extends React.ImgHTMLAttributes<HTMLImageElement> {
src: string | undefined;
Expand All @@ -60,24 +60,6 @@ export interface FormProps extends React.FormHTMLAttributes<HTMLFormElement | HT
className?: HTMLClassNameAttribute;
}

/*
*
* define Custom specific Card Component type properties.
* add any other custom props you want to use.
*
*/
export interface CardProps {
key?: HTMLIdAttribute | number | null | undefined;
url?: string | undefined;
avatar?: string | undefined;
alt?: string | undefined;
children?: React.ReactNode | React.ReactNode[];
className?: string | undefined;
ImageId?: string | undefined;
IconId?: string | undefined;
onClick?: HTMLOnClickAttribute;
}

/*
*
* define Custom Toastify Component type properties.
Expand Down Expand Up @@ -136,4 +118,25 @@ export interface ToastifyProps extends ToastContainerProps {
* @INTERNAL
**/
props?: ToastProps;
}


/*
*
* • `data`: An array of items of type `T` that the component will be iterating over.
* • `renderItem`: A function that takes an item of type `T` as an argument, and returns a
* React node that will be rendered for that item.
*
* generic type parameter `T`, the `MapProps` interface allows you to define the
* type of the data that the component will be iterating over at runtime. This makes the
* component more flexible and reusable, as it can be used with different types of
* data without needing to be rewritten for each type.
*
* • Define the props for the component using a generic type parameter `T`
*
*/

export interface MapProps<T> {
data: T[];
renderItem: (element: T, index: number) => React.ReactNode;
}
65 changes: 30 additions & 35 deletions src/components/UserSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react';
import { API_URL } from '../container/commas';

const Form = React.lazy(() => import('../container/common/Form'));
const Card = React.lazy(() => import('../container/common/Card'));
import Map from '../container/common/Map';

const API_URL = "https://api.github.com";
const Button = React.lazy(() => import('../container/common/Button'));
const Form = React.lazy(() => import('../container/common/Form'));
const Img = React.lazy(() => import('../container/common/Img'));

interface User {
login: string | undefined;
Expand Down Expand Up @@ -57,7 +59,8 @@ const UserSearch: React.FC = (): JSX.Element => {
event?.preventDefault();
/*
*
* Here, 'EventTarget & HTMLInputElement' is a type that represents an object that can be both an 'EventTarget' and an 'HTMLInputElement'.
* Here, 'EventTarget & HTMLInputElement' is a type that represents an object that can be both an
* 'EventTarget' and an 'HTMLInputElement'.
*
* The 'value' property is specific to 'HTMLInputElement' objects, which means that it may not
* exist on all objects that implement the 'EventTarget' interface.
Expand All @@ -68,22 +71,28 @@ const UserSearch: React.FC = (): JSX.Element => {
setQuery(inputValue);
};

/**
* Here we restrict all handleClicks to be exclusively on
* HTMLButtonElement Elements
*
* We're using `MouseEvent` as type for the event.
* with `HTMLButtonElement` as a type parameter.
* It contains properties an event can have
* and methods (such as `preventDefault` an others).
**/
// const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
// 👇️ prevent page refresh
// event?.preventDefault();

// 👇️ redirects to an external URL
// window.open('https://github.com/yagnikvadi2003', '_blank', 'noopener noreferrer');
// };
/*
* This function takes an element of type `User` and an index of type `number` as parameters.
*/
function renderMyDataItem(element: User, index: number): React.ReactNode {
/*
*
* The function returns a React node that renders the markup for the given `User` element.
*
* A `div` element is rendered with a class of `"card"`.
* The `key` attribute is set to the `element.login` value if it exists, otherwise it is
* set to the `index` value.
*
*/
return (
<div className="card" key={element.login ? element.login : index}>
<Img src={element.avatar_url} alt={element.login} ImageId='cardImage' />
<a href={element.html_url} target="_blank" rel="noopener noreferrer">
<Button children='GitHub' className='fa-brands fa-github' id='card-button' />
</a>
</div>
);
}

/*
* 👇️type assertion
Expand All @@ -95,21 +104,7 @@ const UserSearch: React.FC = (): JSX.Element => {
<div className='userSearchHeading'>GitHub User Search</div>
<Form onSubmit={handleSubmit} onChange={handleChange} value={query} InputId='userSearchInput' className='fa-solid fa-magnifying-glass' ButtonId='userSearchButton' />
</div>
{
results.map((element, index): any => {
return (
<Card
key={element.login ? element.login : index}
avatar={element.avatar_url}
alt={element.login}
url={element.html_url}
ImageId='cardImage'
children='GitHub'
className='fa-brands fa-github'
/>
);
})
}
<Map data={results} renderItem={renderMyDataItem} />
</React.Fragment>
);
};
Expand Down
15 changes: 2 additions & 13 deletions src/container/commas.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,2 @@
import axios, { AxiosInstance } from 'axios';

/*
* Create a new instance of Axios
*
* If you are using different URLs, consider removing this line and adding a baseURL in the Axios Config parameter.
*/
export const api: AxiosInstance = axios.create({
baseURL: 'https://api.github.com',
headers: {
"Content-type": "application/json"
}
});
// Get your API key from the environment variables.
export const API_URL = process.env.REACT_APP_API_URL?.trim() || '';
2 changes: 1 addition & 1 deletion src/container/common/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ const Button: React.FC<ButtonProps> = ({ ButtonId, children, className, IconId,
* Usage <Button text='something' className='something' onclick={ClickEvent} />
**/

export default Button;
export default React.memo(Button);
24 changes: 0 additions & 24 deletions src/container/common/Card.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion src/container/common/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ const Form: React.FC<FormProps> = ({ onSubmit, onChange, value, InputId, classNa
* Usage <Form value='SomeThingValue' onChange={ChangeEvents} onSubmit={SubmitEvent} IconId={IconId} ButtonId={ButtonId} />
**/

export default Form;
export default React.memo(Form);
2 changes: 1 addition & 1 deletion src/container/common/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ const Icon: React.FC<IconProps> = ({ className, IconId }): JSX.Element => {
return <i className={className} id={IconId} style={{ padding: "5px" }}></i>;
};

export default Icon
export default React.memo(Icon);
2 changes: 1 addition & 1 deletion src/container/common/Img.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,4 @@ const Img: React.FC<ImgProps> = ({ src, alt, width, height, className, ImageId }
* Usage <Img src='someUrl' alt='something' width={100} height={100} className='something' id='something' />
**/

export default Img;
export default React.memo(Img);
2 changes: 1 addition & 1 deletion src/container/common/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ const Input: React.FC<InputProps> = ({ InputId, type, placeholder, className, va
/**
* Usage <Input type='something' placeholder='something' className='something' value={somethingValue} onChange={something OnChange Event} />
**/
export default Input;
export default React.memo(Input);
16 changes: 16 additions & 0 deletions src/container/common/Map.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { MapProps } from "../../@types/Type";

// Define the component as a function that takes the props as an argument
function Map<T>({ data, renderItem }: MapProps<T>): JSX.Element {
/*
* • Use the `map` method to iterate over the `data` array and render
* the items using the `renderItem` function
*/
return <>{data.map((element, index) => renderItem(element, index))}</>;
}

/*
* • Export the component and its props interface for use in other parts
* of the application
*/
export default Map;
2 changes: 1 addition & 1 deletion src/container/common/Toastify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ const Toastify: React.FC<ToastifyProps> = ({
);
};

export default Toastify;
export default React.memo(Toastify);

0 comments on commit 65dd7bf

Please sign in to comment.