Applications need to store information about their current state. For example, if a user is logged in, we need to remember who they are. If we type in a form, we need to save the values.
There are three places we can store state:
- In the component itself.
- In the root component of the app.
- In a Flux Store, which is like a database for the application.
Depending on what we want to achieve, we may use one or all of these techniques in our application.
Stateful components are defined using a class. Until mid 2016, all components were defined this way, and could potentially have state. Here is an example of a component with state:
There are several things to notice here:
1. We can initialise state anywhere, but unless we do so, state won't be available. Remember your super call, or everything will break.
2. We change state in setState
the setState function lets us change the state for the component. React will pick up on this call, and will rerender the app. This isn't Angular, where you can just change values. There's no magic here.
We never change objects directly in state, we ask setState to do it for us. Real immutability allows us to do some serious speed optimisations. Lots more on this later.
Note also that sometimes React may batch multiple setState commands into one, so you can't guarantee when the state will actually change.
State is immutable
Despite its name, setState doesn't set the entire state, will only change the keys we give it. If we want to set a particular field, we only pass an object containing the field we want to set. Everything else will remain unchanged. React will then update state for us and will be notified to do a erender at its earliest convenience.
Objects in state are immutable. This means that we never change them. Instead, if we want to update them, we create a copy, modify the copy, and save it in the same place. This might sound inefficient. In practice, it's actually rather fast because we can make some assumptions about where our objects are available.
This, for example, is naughty:
Why? because I've directly modified this.state.hero.power. Imagine if this same hero object were shared by multiple components. We would modify it in one place, and it would be updated all over the place, without React knowing. Now we have a broken app.
Here's an example of mutating a shared object. Can you see how all most of the components are showing the wrong data most of the time?