Rafael Menezes

How to update a component state

So in this post I’m gonna try to explain what is a component state and how it works.

In the last post, we added the property state to the App component and we initiate it with a random amount of foods so we can see the list in the page:

...
class App extends React.Component {
  state = {
    consumed: generate(),
  }
...

The name self-explanatory, it holds information about the component’s state during the time it is mounted (showing on the DOM). We can define the initial state values in two ways, one is the way described in the previous snippet where the state is declared as a class property, and the other way is inside a constructor like this:

class SomeComponent extends React.Component {
  constructor(props) {
    super(props) //always required inside a contructor and always the first to be called

    this.state = {
      value: true,
    }
  }
}

When this state changes, react reacts (do you get it? 😉) to this change, triggers a shitload of events and updates, do some internal black magic and in the end re-render, in the DOM, only the relevant parts affected by this change. React is really efficient managing where, when and how to update the view but to be able to do that some constraints had to be stablished so the user don’t mess the process up.

The first rule to update react’s state is, you don’t update the state, you ask react to do it. You do it using the method setState() inherited from the Component class:

class SomeComponent extends React.Component {
  state = {
    value: true,
    someOtherValue: 'hello',
  }

  do_something_in_the_wrong_way = () => {
    this.state = { value: false } // ❌ wrong  }

  do_something_in_the_right_way = () => {
    this.setState({ value: false }) // ✅ ok  }
  ...
}

React does a shallow merge when we use setState(), updating in the state only the properties passed on the call.

Now imagine that we have a class with many different methods and event handlers, and the component state is updated in many different places. If those methods were called in sequence, the rendering would be triggered many times in a short period of time causing a bad impact on the performance. One of the reasons that makes react so efficient is because it batches the updates to the state and triggers the re-rendering when it sees fit. If you’re thinking that this would cause the update to be asynchronous, you are right. When you trigger an update in the state and read it straight away, there is a chance you will get an old value.

This can cause two main issues when we are dealing with the state:

  1. When we update the state based using a value from the state
  2. When you want to trigger a behavior when the state is updated

To overcome the first issue, react allows us to pass a function that returns the object to be merged. In this case, the function will be called when react decide it is time to update it. It’s called a “updater function”:

this.setState((currentState, currentProps) => {
  return { value: !currentState.value }
})

The second issue we can fix in two different ways, one is passing a callback function when we call the setState method, the other is using a Component lifecycle method called componentDidUpdate():

handleEvent = () => {
  this.setState({value: true},
  ()=>{
    //triggers an event after the update
  })
}

componentDidUpdate(){
  //triggers an event after the update
}

That’s it for now. If you have any questions, use the comment section below.

Cheers!