Nosa Obaseki Front-end Dev currently building amazing products @theflutterwave 🐼🇳🇬

An imperative guide to setState in React

3 min read 843

An Imperative Guide To SetState In React

States in React, like props, are objects that are used to store data and affect how the component renders or behaves. Unlike props, states are managed completely within the component and can be changed over time.

The change in state for React components can be a result of triggers from user actions, network activity, API requests or specific application behavior.

Components that have a state are referred to as stateful components while those that do not have states are referred to as stateless components.

A component can have an initial state set, access it and also update it:

import React, { Component } from 'react';

class Food extends Component {
  constructor(props) {
    super(props)

    this.state = {
      fruits: ['apple', 'orange'],
      count: 0
    }
  }
}

In the above code block, we are setting the component’s initial state. This is done through the constructor method.

As mentioned previously, states are plain Javascript objects which is why this.state should be equal to an object:

this.state = {
  fruits: ['apple', 'orange'],
  count: 0
}

Accessing component states

Component states can be accessed like other objects using this.state.property_name.

To access the count in the above example, we can do this by this.state.count:

render() {
  return (
    <div className = "container">
      <h2> Hello!!!</h2>
      <p> I have {this.state.count} fruit(s)</p>
    </div>
  );
}

Updating component states

Although it is technically possible to write to this.state from anywhere in your code, it will not prompt a re-render, and this would lead to unstable and incorrect state values when you try to access the values through this.state.

The only place you should directly write to this.state is the component’s constructor method.

Use the setState() method everywhere else, doing so will accept an object that will eventually be merged into the component’s existing state.

For example, this will not re-render a component:

// Wrong
this.state.name = 'Obaseki Nosa';

Instead, use setState().

Introducing setState()

setState() schedule changes to the component’s state object and tells React that this component and its children need to be re-rendered with the update state:

// Correct
this.setState({name: 'Obaseki Nosa'});

React intentionally “waits” until all components call setState() in their event handlers before starting to re-render. This boosts performance by avoiding unnecessary re-renders.

Know that setState() can be considered as a request instead of an immediate command to update the component.

This is why trying to use this.state immediately after a setState() would lead to incorrect behaviors:

// Trying to change the value of this.state.count from previous example
this.setState({
  count: 4
});

console.log(this.state.count); // 0

this.state.count returns 0 because even though the value has been set with setState(), it was only scheduled and yet to be re-rendered before attempting to use the value with this.state.

setState() will always lead to a re-render unless shouldComponentUpdate() returns false.

Using setState() in React lifecycle methods

Calling setState() in React’s lifecycle methods requires a certain level of caution. There are a few methods where calling setState() would lead to undesirable results and others where it should be avoided completely.

render()

Calling setState() here makes your component a contender for producing infinite loops.

The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it’s invoked, and it does not directly interact with the browser.

In this case, avoid using setState() here.

constructor()

You should not call setState() in the constructor(). Instead, if your component needs to use local state, assign the initial state to this.state directly in the constructor.

componentDidMount()

componentDidMount() is invoked immediately after a component is mounted. You may call setState() immediately in componentDidMount(). It will trigger an extra rendering, but it will happen before the browser updates the screen thus render() will be called twice.

componentDidUpdate()

componentDidUpdate() is invoked immediately after updating occurs. You may call setState() immediately here, but know that it must be wrapped in a condition like in the example below, or you’ll cause an infinite loop:

componentDidUpdate(prevProps, prevState) {
  let newName = 'Obaseki Nosa'
  // Don't forget to compare states
  if (prevState && prevState.name !== newName) {
    this.setState({name: newName});
  }
}

componentWillUnmount()

You should not call setState() here because the component will never be re-rendered. Once a component instance is unmounted, it will never be mounted again.

Conclusion

  1. setState() is async, meaning there is no guarantee that the state has been updated if we try to access the value immediately
  2. You can only change state with setState and React will react to the change 😉
  3. Avoid confusing the state object with other instance properties. It’s easy to assume you can define another object in the constructor and try to use it like state, but the state instance is a special one because React will manage it:
    ...
    //constructor function above
    
    this.state = {
      fruits: ['apple', 'orange'],
      count: 0
    }
        
    this.user = {
      name: 'Obaseki Nosa'
    }
    
    ...

Although both this.state and this.user are objects initialized in the constructor, only this.state reacts with setState() and is managed by React.

Cheers!!!

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, tracking slow network requests and component load time, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors performance of your app with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps - .

Nosa Obaseki Front-end Dev currently building amazing products @theflutterwave 🐼🇳🇬

Leave a Reply