React Tips — Modern Structures and State Updates
Tags: react, webdev, programming, javascript
Published: 2021-01-23 19:55:42

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**


React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps. In this article, we’ll look at some tips and tricks to make building apps with React easier.

### Reduce the Use of Class Components

Class components have issues like dealing with lifecycle hooks and making sure the value of `this` is the correct one.

With the introduction of React hooks, function components are now smart. Therefore, we can use function components like we did we with class components, but without the headache of `this` and lifecycle hooks.

For instance, we can easily create a component that loads something from an API with the `useEffect` hook as follows:

```
import React from "react";

export default function App() {
  const [name, setName] = React.useState({});
  const getName = async () => {
    const res = await fetch("https://api.agify.io?name=michael");
    setName(await res.json());
  };
  React.useEffect(() => getName(), []);
  return <div className="App">{name.name}</div>;
}
```

In the code above, we have the `React.useEffect` call to call an API to get some data on load. We set the data with the `setName` function that’s returned from `React.useState` , which returns a state variable and a function to set the state.

Then we display it in the div that we returned.

To do the same thing with class-based components, we’ve to write the following:

```
import React from "react";

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {};
  }

  async componentDidMount() {
    const res = await fetch("https://api.agify.io?name=michael");
    this.setState({ name: await res.json() });
  }

  render() {
    return <div className="App">{this.state.name.name}</div>;
  }
}
```

As we can see, it’s a bit longer. Also, we have to extend the `React.Component` class to create a class component.

Also, we have to initialize `this.state` in the constructor and also call `super` .

In the `componentDidMount` hook, which is the same as using `useEffect` with an empty array as the second argument, we call the code to load the data that we want from the API.

Then we render the data in the `render` method with the div as we did before, except that we’ve to reference `this.state` to do that.

As we can see, the function component version is shorter. Also, we can use hooks however we see fit, unlike component lifecycle methods, which only run in certain parts of the lifecycle.

For instance, we can change the `useEffect` hook to watch for input value changes and call the API as follows:

```
import React from "react";

export default function App() {
  const [name, setName] = React.useState("");
  const [result, setResult] = React.useState({});
  const getName = async () => {
    const res = await fetch(`https://api.agify.io?name=${name}`);
    setResult(await res.json());
  };
  React.useEffect(() => {
    getName();
    return () => {};
  }, [name]);

  return (
    <div className="App">
      <input onChange={e => setName(e.target.value)} />
      <p>{result.name}</p>
    </div>
  );
}
```

In the code above, we used the `useEffect` hook to watch for the change of the value of `name` by passing `name` into the array of `useEffect` as the second argument.

The `return` statement in the `useEffect` callback is for running any cleanup code if needed.

We then call `getName` in a similar way as before, except that we interpolated `name` in the URL. As we can see, the `useEffect` hook does a lot more than a single lifecycle method in React can do. We did all that without having to reference `this` , which is also great since it’s always confusing.

This is one more reason to use function components with hooks.

### Don’t use Props in Initial State

We shouldn’t use props in the initial state because the constructor is called only once when the component is created.

This means that when we make some changes to props next time, the component state won’t be updated.

The better way to reference props is to do it in `componentDidUpdate` . It’s a lifecycle method that lets us update the component when something change, such as when props change.

For instance, we can call `this.setState` in `componentDidUpdate` as follows:

```
import React from "react";

class Count extends React.Component {
  constructor() {
    super();
    this.state = {
      count: 0
    };
  }
  componentDidUpdate(prevProps) {
    if (this.props.count !== prevProps.count) {
      this.setState({ count: this.props.count * 2 });
    }
  }
  render() {
    return <div>{this.state.count}</div>;
  }
}

export default function App() {
  const [count, setCount] = React.useState(0);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Count count={count} />
    </div>
  );
}
```

In the code above, we check if `prevProps.count` ‘s value is different from `this.props.count` ‘s the value before calling `this.setState` so that we don’t call it repeatedly and unstoppably. Then we render `this.state.count` that we set in the `render` method.

This is the right because we’re updating the state according to the value of the prop. We should get the count displaying the `count` prop passed in `App` multiplied by 2.

If it’s in the constructor, then `this.state.count` won’t update because it won’t update when the props change as we have in our example.

### Conclusion

With the introduction of hooks, it’s time to embrace function components and hooks together to create stateful components. It reduces the headaches with dealing with lifecycle methods and the value of `this` .

Also, if we’re using class components, then we have to remember not to set props as the value of a state property in the constructor, because the prop will never update the state after the first time the component loads. Instead, we should call `setState` in `componentDidUpdate` to update the state with our prop value.