6 React Best Practices For 2021
Tags: react, webdev
Published: 2021-02-10 16:57:18

_by author [Michiel Mulders](https://blog.asayer.io/michiel-mulders/)_
Writing clean and readable code is essential to improve your code’s quality. On top of that, clean code is easier to test. There’s no reason not to spend five extra minutes refactoring your code to make it more readable.

This article looks at six React best practices for 2021 to improve your code. We’ll cover the following items:


1. Make use of `event.target.name` for event handlers
2. How to avoid manually binding event handlers to `this`?
3. Make use of React hooks to update your state
4. Cache expensive operations with `useMemo`
5. Decouple functions into functional functions to improve code quality
6. How do you create custom hooks in React?


## #1: Use event handler name

When you have a form with a single input field, you’ll write one `onFirstInputChange` function to capture the contents of your input field.

However, do you write ten event handlers when you have a form with ten input fields? The answer is no.

We can set the name property on an input field and access it from the event handler. This value allows us to use a single input handler for `onChange` events. 

Here’s your current situation when using a not-optimized form with two input fields. We have to define an `onChange` event handler for each individual form input element. This pattern creates a lot of duplicate code, which is hard to maintain.

```js
export default class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            item1: "",
            item2: "",
            items: "",
            errorMsg: ""
        };
        this.onFirstInputChange = this.onFirstInputChange.bind(this);
        this.onSecondInputChange = this.onSecondInputChange.bind(this);
    }
    onFirstInputChange(event) {
        const value = event.target.value;
        this.setState({
            item1: value
        });
    }
    onSecondInputChange(event) {
        const value = event.target.value;
        this.setState({
            item2: value
        });
    }
    render() {
        return (
            <div>
                <div className="input-section">
                    {this.state.errorMsg && (
                        <p className="error-msg">{this.state.errorMsg}</p>
                    )}
                    <input
                        type="text"
                        name="item1"
                        placeholder="Enter text"
                        value={this.state.item1}
                        onChange={this.onFirstInputChange}
                    />
                    <input
                        type="text"
                        name="item2"
                        placeholder="Enter more text"
                        value={this.state.item2}
                        onChange={this.onSecondInputChange}
                    />
                </div>
            </div>
      );
    }
}
```

As you can see, each event handler function updates the state. When dealing with multiple form elements, your code becomes very messy as you have to write a new function for every event.

Let’s tackle this situation differently using the `name` field. We can access this value via the `event.target.name` property. Now, we can create a single function that can handle both events at once. Therefore, we can remove both functions `onFirstInputChange` and `onSecondInputChange`.

```js
onInputChange = (event) => {
  const name = event.target.name;
  const value = event.target.value;
  this.setState({
    [name]: value
  });
};
```

Easy, right? Of course, you often need additional validation for the data you save to your state. You can make use of a `switch` statement to add custom validation rules for each submitted value.


## #2: Avoid manually binding `this`

You will most likely know that React doesn’t retain the `this` binding when attaching an event handler to an `onClick` or `onChange` event. Therefore, we need to bind `this` manually. *Why do we bind* `*this*`*?* We want to bind the `this` of the event handler to the component’ instance, so we don’t lose its context when we pass it as a callback.

Here’s a classic “binding” example that happens in the constructor.

```js
class Button extends Component {
  constructor(props) {
    super(props);
    this.state = { clicked: false };
    this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick() {
    this.props.setState({ clicked: true });
  }
  
  render() {
    return <button onClick={this.handleClick}>Click me!</button>;
  );
}
```

Yet, binding is not necessary anymore since the `create-react-app` CLI command makes use of `@babel/babel-plugin-transform-class-properties` plugin version >=7 and `babel/plugin-proposal-class-properties` plugin version <7. 


> Note: You have to change the event handler syntax to arrow function syntax.

Below you find an example of the arrow function syntax. Here, we don’t need to write additional code in the constructor to bind `this`.

```js
class Button extends Component {
  constructor(props) {
    super(props);
    this.state = { clicked: false };
  }
  
  handleClick = () => this.setState({clicked: true });
  render() {
    return <button onClick={this.handleClick}>Click me!</button>;
  );
}
```

That’s as simple it can get! You don’t need to worry about binding functions in your constructor.


## #3: Use React hooks to update your state

Since React version 16.8.0, it’s now possible to use state and lifecycle methods inside functional components using React Hooks. In other words, we can write better readable code that’s also much easier to maintain.

For this, we’ll be using the `useState` hook. For those that are not aware of what a hook is and why you would use it. Here’s a short definition from the [React documentation](https://reactjs.org/docs/hooks-state.html#whats-a-hook).


> **What is a Hook?** A Hook is a special function that lets you “hook into” React features. For example, useState is a Hook that lets you add React state to function components.


> **When would I use a Hook?** If you write a function component and realize you need to add some state to it, previously you had to convert it to a class. Now you can use a Hook inside the existing function component.

First, let’s take a look at how we update the state using the `setState` hook.

```js
this.setState({
    errorMsg: "",
    items: [item1, item2]
});
```

Now, let’s make use of the `useState` hook. We need to import this hook from the `react` library. We can now declare new state variables and pass them an initial value. We’ll use destructuring to get a variable for retrieving the value and one for setting the value (this one is a function). Let’s take a look at how we can do this for the above example.

```js
import React, { useState } from "react";

const App = () => {
  const [items, setIems] = useState([]);
  const [errorMsg, setErrorMsg] = useState("");
};

export default App;
```

Now, you can directly access both constants `items` and `errorMsg` in your component.

Further, we can update the state inside a function like this:

```js
import React, { useState } from "react";

const App = () => {
  const [items, setIems] = useState([]);
  const [errorMsg, setErrorMsg] = useState("");

  return (
    <form>
        <button onClick={() => setItems(["item A", "item B"])}>
          Set items
        </button>
    </form>
  );
};

export default App;
```

That’s how you can use state hooks.


## #4: Cache expensive operations with useMemo

Memoization is an optimization technique to store the result of expensive operations. In other words, a sorting operation is often an expensive operation that requires a lot of processing. We don’t want to execute this expensive function for every page render.

Therefore, we can use the `useMemo` hook to remember the output when you pass the same parameters to the [memoized function](https://rossbulat.medium.com/how-to-memoize-in-react-3d20cbcd2b6e). The `useMemo` hook accepts a function and the input parameters to remember. React refers to this as a dependencies array. Every value referenced inside the function should also appear in your dependencies array.

Here’s a simple, abstract example. We pass two parameters `a` and `b` to an expensive function. As the function uses both parameters, we’ve to add them to the dependencies array for our `useMemo` hook.

```js
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
```


## #5: Decouple functions into pure functions to improve code quality

As a general React best practice, you should decouple functions that don’t rely on your component. In other words, a function that doesn’t rely on any state or React hooks.

Therefore, a sorting function is an excellent example of a function that you can extract as a pure function. 

You might wonder why you should embrace functional programming? 


> Functional programming is the process of building software by composing pure functions, avoiding shared state, mutable data, and side-effects. Pure function are better readable and easier to test. Therefore, they improve code quality. - [freeCodeCamp](https://www.freecodecamp.org/news/intro-to-functional-programming-basics/)

Now, let’s apply this concept to React components. Here’s a function that can sit both inside a React component or outside. Both are comparison functions, which you can pass to an expensive sorting function, that accept two input parameters. As there’s no interaction with the state, we can extract both functions to pure functions. This allows us to place the pure functions in a separate file and import them in multiple locations if needed.

```js
function ascSort (a, b) {
  return a < b ? -1 : (b > a ? 1 : 0);
}

function descSort (a, b) {
  return b < a ? -1 : (a > b ? 1 : 0);
}
```


## #6: Create custom React hooks

We’ve learned how to use the `useState` and `useMemo` React hooks. Yet, React allows you to define your own React hooks to extract logic and make components more readable. 

We can specify custom React hooks starting with the `use` keyword, like all other React hooks. It’s beneficial when you want to share logic between different functions. Instead of copying the function, we can define the logic as a React hook and reuse it in other functions.

Here’s an example of a React component that updates the state when the screen size gets reduced to below 600 pixels. If this happens, the `isScreenSmall` variable is set to `true`. Otherwise, the variable is set to `false`. We use the `resize` event from the window object to detect screen size changes.

```js
const LayoutComponent = () => {
  const [onSmallScreen, setOnSmallScreen] = useState(false);

  useEffect(() => {
    checkScreenSize();
    window.addEventListener("resize", checkScreenSize);
  }, []);

  let checkScreenSize = () => {
    setOnSmallScreen(window.innerWidth < 768);
  };

  return (
    <div className={`${onSmallScreen ? "small" : "large"}`}>
      <h1>Hello World!</h1>
    </div>
  );
};
```

Now, we want to use the same logic in another component that relies on this `isScreenSmall` variable. Instead of duplicating the code, let’s transform this example into a custom React hook.

```js
import { useState, useEffect } from "react";

const useSize = () => {
  const [isScreenSmall, setIsScreenSmall] = useState(false);

  let checkScreenSize = () => {
    setIsScreenSmall(window.innerWidth < 600);
  };
  useEffect(() => {
    checkScreenSize();
    window.addEventListener("resize", checkScreenSize);

    return () => window.removeEventListener("resize", checkScreenSize);
  }, []);

  return isScreenSmall;
};

export default useSize;
```

We can create a custom React hook by wrapping the logic in a `use` function. In this example, we named the custom React hook `useSize`. Now we can import the `useSize` hook anywhere we require it.


> React custom hooks are nothing new. You wrap the logic with a function and provide it a name that starts with `use`. It acts like a normal function. However, by following the starts with “use” convention, you´re telling anyone who´s importing it, that it is a hook. Furthermore, because it is a hook, you should structure it in a way that [follows the rules of hooks](https://reactjs.org/docs/hooks-rules.html).

Here’s how our component looks like now. The code becomes much cleaner!

```js
import React from 'react'
import useSize from './useSize.js'

const LayoutComponent = () => {
  const onSmallScreen = useSize();

  return (
    <div className={`${onSmallScreen ? "small" : "large"}`}>
      <h1>Hello World!</h1>
    </div>
  );
}
```

## Bonus tip: Frontend monitoring
Monitoring your frontend is mandatory if you're looking to undertand what you're users are doing and how is your application responding to those requests.
[Asayer](https://asayer.io) is a frontend monitoring tool that replays everything your users do and shows how your web app behaves for every issue. It lets you reproduce issues, aggregate JS errors and monitor your web app’s performance.
 
[Start monitoring your web app for free](https://asayer.io/register.html).


That’s it! This article has taught you six techniques to improve code readability and code quality.