React Naming Conventions:
Component Naming Conventions:
- Use PascalCase for react component names, Interfaces & Types:
const ColumnSelectorPropsType = { heading: string };
const ColumnSelector = ({ heading }: ColumnSelectorPropsType) => {
return <div className="column-selector">{heading}</div>;
};
- Only one component per file
- Use component name for filename
- Use .tsx extension for the component file.
- All files related to a component must be inside the component folder
ColumnSelector.tsx
- Use camelCase for component instances/Javascript objects/non-component.
const FileUploader = <FileUploader file={} setFile={}/>
- Use component name associated style (.css/.scss/**.js) file name should be in Pascal Case. If there is more than one component ( sub-component ) then it is better to create style folder then add all styled component.
FileUploader.style.ts
- Add Import React statement in every react component file in single quote.
import React from 'react';
Property/Attribute Naming Conventions:
- Use camelCase for property/attribute names
<workbench exceptionType="UOM" refreshInterval={3000}/>
- Use double quotes for JSX/TSX attributes, use single quotes for js strings.
const exceptionType = 'VPXD';
<ColumnSelector heading="Select Columns" exceptionType={exceptionType}/>
- If the value of the component property is 'true' you don't need to mention it.
const File = ({showFile:boolean, salesId: number}) => {
const filePath = `.../file/${salesId}`;
return (<div className="user"> salesId:{salesId} <a href={fileP/>{filePath}</a> </div>);
<File salesid="12345" showFile={true}/>
//change it to
<File salesid="12345" showFile/>
- Always use propsWithChildren when you pass children to a component
import React, {propsWithChildren} from 'React';
type ComponentProps = {name:string};
const Component=(props:PropsWithChildren<ComponentProps>)=>{...};
Anything to be added in future.
Folder Naming Conventions:
User camelCase for folder names
Use index.js in every folder and export all modules from that folder. This way we can directly import modules from the folder without the complete path.
//folder structure
ColumnSelector - ColumnSelector.tsx
- ColumnSelectro.scss/ColumnSelectro.css
- index.tsx
index.js
export * from './ColumnSelector';
- Folder which having component should follow naming convention as camel case.
Custom Hooks Naming Conventions:
- Create custom hooks in separate files inside hooks folder.
- Custom hook should start with the string "use". e.g useChangeLog
Component Development Guidelines:
- Separate large inline function from the JSX/TSX:
const Button = () => <button onClick={(event:any)=> console.log(event)} value="Save"/>
//Change to below:
const Button = () => {
const onClick = (event:any)=> console.log(event);
return (<button onClick={onClick} value="Save"/>);
}
- Avoid using indexes as key props to re-render components, instead use unique keys generated by API response.
const list = (<ul>{storeList.map((store,idx,storeList)=>(<li key={idx}>{store.value}</li>))}</ul>);
//change to:
const list = (<ul>{storeList.map((store,idx,storeList)=>(<li key={store.id}>{store.value}</li>))}</ul>);
Group the state variables into a single state whenever possible
const [fileName, setFileName] = useState("");
const [fileState, setFileState] = useState("");
//change it to:
const [file, setFile] = useState({fileName:"", fileState:""});
Avoid Inline styles, use CSS style based components.
Avoid long list of arguments for functions, use objects instead
const getBottomRight = (top:number, left:number, width:number, height:number) => {
return { left: left+width, top: top+height };
}
//change to
const getBottomRight = ( {top, left, width, height} : any) => {
return { left: left+width, top:top+height };
}
- Use template literals instead of string concatenations
const SalesId = 3089089;
const isZipFile = true;
const API = "/switch-user?salesID="+SalesId+"&isZipFile="+ isZipFile;
//change it to
const API = `/switch-user?salesID=${SalesId}&isZipFile=${isZipFile}`;
- Ensure to remove non-html attributes before applying to the jsx.
const saveBtn = ({hide,...rest}:any) => {
return <button {...rest} style={visibility:hide}/>;
}saveBtn({value:"save", onClick:()=>{}, hide});
- Use closing tags for components when there are no children
<FileUploader></FileUploader>
//change it to
<FileUploader/>
- Keep imports in a consistent order
1) Frame work imports: import React from 'react'
2) External Library imports: import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
3) Internal Library imports: import { Loader } from '@replenishments/react-components';
4) project imports: import useChangeLog from '../hooks/useChangeLog';
- Use Object De-structuring
const Profile = (user:any) => (<div className='user-info'> {profile.salesId}|{profile.name}|{profile.profileType} </div>);
//change it to
const {salesId, name, profileType} = profile;
const Profile = (user:any) => (<div> {salesId}|{name}|{profileType} </div>);
- Use functional components instead of class-based components
- Try to segregate API call related logic from actual Component.
- You can create simple js or ts file and have API call level logic into that file as a function. And whenever you needed import and use this will help to write unit test case.
- Any utility function should not be the part of Component container. Please write outside the container.
When you passing props from parent to child please define interface in child component.
If possible, move data fetching logic into container components for clean code
const UserList = ()=>{
const [users, setUsers ] = useState([]);
useEffect(() => {
fetch("../users").then((res) => res.json()) .then(({ users }) => setUsers(users));
}, []);
return <div className='user-list'><ul> {users.map((user:any)=><li>{user.name}</li>)}</ul></div>;
}
//Change it to
const useFetchUsers = (setUsers:any) => {
useEffect(() => {
fetch("../users").then((res) => res.json()) .then(({ users }) => setUsers(users));
}, []);
}
const UserListContainer = ()=>{
const [users, setUsers ] = useState([]);
useFetchUsers(setUsers);
return <UserListPresentation userList={users}/>;
}const UserListPresentation = ( userList:any[]) => {
<div className='user-list'><ul> {users.map((user:any)=><li>{user.name}</li>)}</ul></div>;
}
- Use Proptypes for properties and define types for each property
- Define default values for properties
- Avoid prop-drilling & prop-polyadic, use redux or context API, and spread props as needed.
- Use refs only when needed
- Use React.memo() for memoizing components for performance optimisations
- Move global constants to a separate constants file. Component-specific constants into a constant file inside the component folder.
- Never call a functional Component like a simple function Sanitise HTML to avoid XSS attacks
Top comments (1)
While index.js files allow for cleaner imports, if you are building something for mobile devices and want to leverage lazy loading to reduce your bundle size, you might want to think twice about how much you export through index.js files.