If you started coding not too long ago, you probably learned React with a bunch of tutorials and hands on guides.
I know we should all read the docs first, but they can be hard to understand for complete newcomers. Coding tutorials, on the other hand, can be superficial and skip over some more advanced concepts, which leaves you making stupid mistakes or writing inefficient code. They also can create the illusion of completeness: You finished the tutorial, therefore now you know and understand everything, right?
After more than 4 years of experience with React, here are some concepts about the React useState hook that I learned the hard way:
1. Always update state with the setState function
You probably did know that, but do you know why that is?
In React, the value stored as state should be treated as immutable. If you want to update your state, you are required to use the setState function with a new value. If you try to update your state directly, React will fail to notice the update and will not rerender your component nor update the state itself.
If you want to store state inside a component that doesn't trigger rerenders, use the useRef hook.
2. There are two ways to initialize state
Did you know you could initialize state with a function too?
Remember that the initial value is evaluated only the first time the component renders. If you pass in a function as an argument, it can't have parameters and it should be self-contained - no randomness or side effects are allowed. Pros refer to these as 'pure functions'.
// ✅ do this:
const [state, setState] = useState(() => createEmptyTodo());
// 🚩 not this:
const [state, setState] = useState((username) => createRandomUser(username));
Use this approach when you need to initialize state with the result of a computationally expensive function or if you want to avoid placing an entire function inside the useState initializer.
3. You can use the previous state in your setter function
Sometimes we forget about the asynchronous nature of the useState hook and try to update it several times inside the same event, ending up with unexpected behavior.
// 🚩 this won't work as expected!
function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}
React does batch setState calls together and rerenders the component afterwards, which is why we have to be careful with the values we pass into the setState function. To avoid bugs, we can pass in an updater function instead of passing in the value directly. This will keep track of the "pending state" (state that has already been updated although it's not yet rendered) and will make the previous code snippet work.
// ✅ this will work
function handleClick() {
setAge(a => a + 1); // setAge(42 => 43)
setAge(a => a + 1); // setAge(43 => 44)
setAge(a => a + 1); // setAge(44 => 45)
}
Understanding this will save you from a lot of headache when you run into issues where your state isn't updating properly.
4. How to Update Objects Correctly
Remember the first part of this article, where we said that state was immutable?
This is important for objects! Every time we want to update a part of an object, we have to pass in a completely new object into our set function. The most common way of doing this is by using the spread operator.
// ✅ Replace state with a new object
setForm({
...formData,
firstName: 'Juan'
});
Also remember that you can overwrite existing object properties by adding them a second time to the object.
/* this will set {
firstName: 'Juan',
lastName: 'Gonzales'
} */
setForm({
firstName: 'Sara',
lastName: 'Gonzales',
firstName: 'Juan'
});
5. You can reset the component's state with the key prop
In React, you normally use the key prop whenever you need to render an array of items.
But you can also give individual components a key prop and change it when you want to reset their state. Whenever the key changes, the whole component and its children are newly created and therefore all existing state vanishes. If you need to reset the state from inside the component, the best way to do this is to store the original state in a variable and use it for overwriting the modified state.
<FormComponent key={selectedProduct} name={selectedProduct} />
You can read more about his behavior in the official react docs.
Knowing and understanding the basics will accelerate your coding journey. Do you want me to analyze more hooks? Let me know in the comments.
Top comments (0)