MWAN MOBILE

×
mwan_logo
blog-banner

10 Essential React Best Practices for Clean and Efficient Code

Programming 05-Sep-2023

Introduction

React has become the go-to library for building user interfaces, and while it’s easy to get started, writing scalable and maintainable React code requires a commitment to best practices. In this blog post, we’ll explore 10 essential React best practices that will help you write clean, efficient, and robust code for your projects.

1. Component Organization:

Organize your components based on their functionality and responsibilities. Use folders to group related components, and consider using a common folder structure like the “containers” and “components” pattern for a clear separation of concerns.

my-react-app/
  |- public/
  |  |- index.html
  |  |- ...
  |
  |- src/
  |  |- components/
  |  |  |- Header/
  |  |  |  |- Header.js
  |  |  |  |- Header.css
  |  |  |
  |  |  |- Footer/
  |  |  |  |- Footer.js
  |  |  |  |- Footer.css
  |  |  |
  |  |- pages/
  |  |  |- Home/
  |  |  |  |- Home.js
  |  |  |  |- Home.css
  |  |  |
  |  |  |- About/
  |  |  |  |- About.js
  |  |  |  |- About.css
  |  |  |
  |  |- utils/
  |  |  |- api.js
  |  |  |- helperFunctions.js
  |  |  |- ...
  |
  |- App.js
  |- index.js
  |- styles.css
  |- ...




2. Functional Components and Hooks:

Prefer functional components over class components whenever possible. Functional components with React Hooks are more concise, easier to read and perform better. There will be no requirement to use the ‘this’ keyword in the functional component.

import React from 'react';

const FunctionalComponent = () => {
  const [count, setCount] = React.useState(0);

  const handleIncrement = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleIncrement}>Increment</button>
    </div>
  );
};

3. State Management:

For state management, embrace React’s built-in useState and useReducer hooks for local state. For more complex global state management, consider using a state management library like Redux, Recoil, Zustand, etc.

import React, { useReducer } from 'react';

const reducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    default:
      return state;
  }
};

const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  const handleIncrement = () => {
    dispatch({ type: 'INCREMENT' });
  };

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={handleIncrement}>Increment</button>
    </div>
  );
};

4. Immutability:

Follow the principle of immutability to avoid unintended side effects and improve performance. Never modify the state or props directly as there will be no re-rendering; instead, create new objects or arrays when updating the state.

5. Key Prop in Lists:

When rendering lists of elements, always provide a unique “key” prop to each item. This allows React to efficiently update and re-render only the necessary components, reducing potential bugs and unnecessary re-renders.

import React from 'react';

const TodoList = ({ todos }) => {
  return (
    <ul>
      {todos.map((todo) => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  );
};

6. Conditional Rendering:

Use conditional rendering to display different components or content based on certain conditions. Utilize ternary operators or the && operator to keep the JSX concise and readable.

Using ternary operator:

import React from 'react';

const ConditionalRender = ({ isLoggedIn }) => {
  return isLoggedIn ? <p>Welcome, user!</p> : <p>Please log in.</p>;
};

Using && operator:

import React from 'react';

const ConditionalRender = ({ isLoggedIn }) => {
  return isLoggedIn && <p>Welcome, user!</p>;
};

7. Extracting Reusable Components:

Identify repeating UI patterns and extract them into reusable components. This promotes a DRY (Don’t Repeat Yourself) code base and makes maintenance clean and easier.

Reusable Button component:

import React from 'react';

const Button = ({ text, onClick }) => {
  return <button onClick={onClick}>{text}</button>;
};

export default Button;




Usage in other components:

import React from 'react';
import Button from './Button';

const App = () => {
  const handleClick = () => {
    // Handle button click
  };

  return (
    <div>
      <Button text="Click me" onClick={handleClick} />
    </div>
  );
};

8. Perfomance Optimization:

Optimize performance by implementing techniques like code splitting, lazy loading, and memoization. Use tools like React’s built-in React.memo or useMemo hooks to prevent unnecessary re-renders.

import React, { useMemo } from 'react';

const ExpensiveComponent = ({ data }) => {
  const result = useMemo(() => {
    // Expensive calculations based on data
    // ...

    return 'Result: ...';
  }, [data]);

  return <div>{result}</div>;
};

9. Prop Types and Typescript:

Enforce strong typing in your React applications using either Prop Types or Typescript. This catches potential bugs early and improves the overall code quality.

Prop Types:

import React from 'react';
import PropTypes from 'prop-types';

const Person = ({ name, age }) => {
  return (
    <div>
      <p>Name: {name}</p>
      <p>Age: {age}</p>
    </div>
  );
};

Person.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
};

export default Person;

Typescript:

import React from 'react';

interface PersonProps {
  name: string;
  age: number;
}

const Person: React.FC<PersonProps> = ({ name, age }) => {
  return (
    <div>
      <p>Name: {name}</p>
      <p>Age: {age}</p>
    </div>
  );
};

export default Person;

10. Error Handling:

Implement proper error handling in your components. Use try-catch blocks in life-cycle methods or Error Boundaries to gracefully handle errors and prevent application crashes.

import React, { useState } from 'react';

const ErrorComponent = () => {
  const [errorMessage, setErrorMessage] = useState('');

  const handleClick = () => {
    try {
      // Simulate an error by accessing a non-existent property
      const undefinedVar = null;
      console.log(undefinedVar.nonExistentProperty);
    } catch (error) {
      // Handle the error gracefully
      setErrorMessage('Something went wrong. Please try again later.');
    }
  };

  return (
    <div>
      <button onClick={handleClick}>Trigger Error</button>
      {errorMessage && <div>{errorMessage}</div>}
    </div>
  );
};

export default ErrorComponent;

Conclusion

By following these ten React best practices, you’ll be able to build more maintainable, performant, and scalable React applications. Remember to always strive for simplicity, readability, and consistency in your code base. Happy coding!

Source: Medium