DEV Community

Cover image for Best Practices for Writing Clean React Code with Examples
Vishesh Tiwari
Vishesh Tiwari

Posted on

Best Practices for Writing Clean React Code with Examples

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>;
};

Enter fullscreen mode Exit fullscreen mode
  • 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.

Image description

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}/>
Enter fullscreen mode Exit fullscreen mode
  • 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/>
Enter fullscreen mode Exit fullscreen mode

 

  • Always use propsWithChildren when you pass children to a component
import React, {propsWithChildren} from 'React';
type ComponentProps = {name:string};
const Component=(props:PropsWithChildren<ComponentProps>)=>{...};
Enter fullscreen mode Exit fullscreen mode

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';
Enter fullscreen mode Exit fullscreen mode

     

  • 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"/>);
}
Enter fullscreen mode Exit fullscreen mode
  • 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:""});
Enter fullscreen mode Exit fullscreen mode
  • 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 };
}
Enter fullscreen mode Exit fullscreen mode
  • 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}`;
Enter fullscreen mode Exit fullscreen mode
  • 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/>
Enter fullscreen mode Exit fullscreen mode
  • 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>);
Enter fullscreen mode Exit fullscreen mode
  • 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>;
}
Enter fullscreen mode Exit fullscreen mode
  • 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)

Collapse
 
brense profile image
Rense Bakker

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.