What are good practices

Good practices in programming are a set of techniques and recommendations that have been developed over time to help programmers create quality code. Some of these practices include:

  • Writing clean, readable code that follows coding standards and community best practices.
  • Using comments and documentation to explain code and make it easier for other programmers to understand.
  • Running unit and acceptance tests to ensure the code works correctly and meets requirements.
  • Using version control to track changes and enable collaboration with other programmers.
  • Using tools and libraries that help improve code quality, such as linters and debuggers.

Examples with React

Use React.Fragment

With React.Fragment you can avoid extra tags like div or span when you want to group elements in a component. This is useful when you want to avoid adding extra elements to the HTML and keep the code more readable and maintainable.

For example, instead of writing:

js
const Component = () => {
  return (
    <div>
      <h1>Title</h1>
      <p>Paragraph</p>
    </div>
  );
};

You can use React.Fragment like this:

js
const Component = () => {
  return (
    <React.Fragment>
      <h1>Title</h1>
      <p>Paragraph</p>
    </React.Fragment>
  );
};

This way you avoid extra tags in the HTML and keep the code more readable and maintainable. Also, in recent versions of React you can use shorthand syntax for React.Fragment, which is simply <> and </>. So the previous example can be written like this:

js
const Component = () => {
  return (
    <>
      <h1>Title</h1>
      <p>Paragraph</p>
    </>
  );
};

Keep business logic and presentation separate

Heads up! Thanks to custom hooks, you no longer need to separate logic and presentation with components.

Presentation components (also called view components) handle how data is displayed in the user interface. These components are usually “pure”: they have no internal state and render deterministically based on their props.

Container components (also called smart components), on the other hand, have internal state and handle business logic. These components are usually “impure” because they can have side effects such as making server requests or updating local state.

Separating business logic and presentation into different components can help make code more maintainable and easier to understand. For example, if you have a TodoList component, you can write it like this:

js
const TodoList = () => {
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    // fetch the todo list
  }, []);

  return <TodoListView todos={todos} />;
};

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

In this example, TodoList is a container component with internal state that fetches the todo list. TodoListView, on the other hand, is a presentation component that simply displays the list in an unordered list.

By separating business logic and presentation into different components, the code is easier to understand and maintain over time. You can also reuse presentation components in different parts of the application without duplicating code.

Use key

Use key to uniquely identify items in a list. When rendering a list of elements in React, it is important to provide a key prop for each item. This lets React identify each element uniquely and improves performance when updating the list.

For example, if you have a TodoList component that renders a list of todos, you can use key like this:

js
const TodoList = () => {
  const [todos, setTodos] = useState([]);

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

In this example, key provides a unique value for each list item. The key value should be stable and unique within the list. Here, the todo ID is used as the key because it does not change and is unique for each todo.

Using key is important for list update performance and for avoiding common errors. If you do not provide a key for each list item, React may show a warning in the browser console and performance can suffer.

Use React.memo or useMemo

React.memo is a way to optimize React component performance by preventing re-renders when props have not changed. When a component receives props that rarely change, re-rendering it on every change elsewhere in the app is often unnecessary. This can save processing time and improve overall application performance.

js
import React from "react";

const MyComponent = ({ prop1, prop2 }) => {
  // The component re-renders only if prop1 or prop2 change
  return (
    <div>
      {prop1} - {prop2}
    </div>
  );
};

// React.memo is used to optimize component performance
export default React.memo(MyComponent);

The useMemo hook works similarly, but instead of applying to a component, it applies to a specific part of a component’s logic.

js
import React, { useMemo } from "react";

const MyComponent = ({ prop1, prop2 }) => {
  // expensiveComputation is recalculated only if prop1 or prop2 change
  const expensiveComputation = useMemo(() => {
    let result = 0;
    for (let i = 0; i < 1000000; i++) {
      result += i;
    }
    return result;
  }, [prop1, prop2]);

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

export default MyComponent;

In other words, React.memo is used at the component level to avoid re-rendering an entire component when its props have not changed, while useMemo is used at the logic level inside a component to avoid recalculating a value when its inputs have not changed.

Avoid calling setState on an unmounting component

When a React component unmounts, it is no longer used in the UI and will be removed by React. If you call setState on a component that is unmounting, unexpected errors can occur because the component is no longer in a valid state and may not have access to its props or state.

js
import React, { useEffect } from 'react';

const MyComponent = ({ prop1, prop2 }) => {
  useEffect(() => {
    // Subscription or timer
    const subscription = someAPI.subscribe(handleData);
    const timer = setInterval(doSomething, 1000);

    // Unsubscribe or clear the timer in the component cleanup
    return () => {
      subscription.unsubscribe();
      clearInterval(timer);
    };
  }, []);

  // Component logic
  ...

  return (
    <div>
      ...
    </div>
  );
};

export default MyComponent;

There are many more good practices in React, and it is important to always look for ways to write maintainable, readable, and efficient code. Thanks for reading, I hope this was helpful!