What, When, Why?
As a web developer, many are familiar with the Javascript library known as React. You may have also heard of React Hooks. Since their introduction in React 16.8 (released Feb. 16, 2019), they've become an integral part of the React environment. These Hooks can be extremely useful and provide a lot of functionality. In this blog, I will cover the React Hook known as useState
discussing how to set it up and how to use it.
React Hooks
“React Hooks are simple JavaScript functions that we can use to isolate the reusable part from a functional component. Hooks can be stateful and can manage side-effects.” - freecodecamp.org
What is useState?
The React Hook useState
allows us to add and access the state of functional components. So how does this help us? It allows our data to be dynamic. Which in return, grants us the ability to re-render and update our application based on events or something that the user has done. Let's take for example a counter app. If a user clicks on a button to increment the counter we want to update the counter dynamically. We can do this with useState
. When it comes to the debate whether to use prop or state, you can ask yourself these 3 questions:
The Questions
- Is it passed in from a parent via props?
- Can you compute it based on any other state/props in your component?
- Does it remain unchanged over time?
If you answer no to all of these questions, then you should probably use useState
.
The How To
Let's talk about how to incorporate useState
into your code. We'll use our counter component from earlier as an example. Here's what that component might look like without useState
:
import React from 'react'
function Counter () {
let count = 0;
function handleClick () {
count++;
}
return (
<div>
<p>{count}</p>
<button onClick={handleClick}>press to increase</button>
</div>
);
};
Although this is functional, our component is not actually re-rendering as we increment. Also, the count
variable goes back to 0
as soon as we refresh the page. Let's add state to fix these issues.
Import it
First we need to import useState
into our component. This is pretty straightforward; at the top of your code (or in whatever component you need it) you want to import it from React by using the destructing syntax (aka this one { } ). This is what that would look like:
import React, { useState } from 'react'
Declare it as a variable
Next we want to replace our count
variable with our useState
variable. To do this, we can call the useState
hook by using the array destructuring syntax. This is what that would look like:
const [count, setCount] = useState(0);
The reason why we use brackets for useState
is because it will always return an array with 2 variables:
- a reference to the current value of that state in React's internals
- a setter function so we can update that state
Technically, the name of the reference and setter function are arbitrary so feel free to call them whatever you like. As good practice you use the naming convention for the setter function as 'set' followed by the reference variable name. Another neat thing is that you can set the initial useState
to various different data types; strings, objects, arrays, numbers, booleans, empty or not can all be set as the initial useState
.
Setting the state
Now that we've called the useState
hook into our component we need a way to update the state and re-render the page with the correct value. This is where our setter function comes in handy. All we need to do is pass our state and increment it by 1
inside our handleClick()
function:
function handleClick() {
setCount((count) => count + 1);
}
After incorporating all these steps, we should now have a working increment button that updates our count
state dynamically as the user clicks the button. Even if the page is refreshed the count
state will remain the same. Here is the code as a whole:
import React, { useState } from 'react'
function Counter () {
const [count, setCount] = useState(0);
function handleClick () {
setCount((count) => count + 1);
}
return (
<div>
<p>{count}</p>
<button onClick={handleClick}>press to increase</button>
</div>
);
};
Mutating State!!
Let's talk about the setter function for one moment. From React's documentation, it's written:
"But you shouldn't change objects that you hold in the React state directly. Instead, when you want to update an object, you need to create a new one (or make a copy of an existing one), and then set the state to use that copy." - React Docs: Updating Objects in State
In the example earlier, our setter function does the following:
- Creates a copy of the state
- Add's 1 to the copy
- Set's the copy state as the state
This is important to keep in mind. If I tried to just update the state like this:
function handleClick () {
count++
setCount(count);
}
the component doesn't actually re-render with a new value. The reason this happens is because we're not providing a new value to setCount
when it's called. Even though we mutated the value, its value did not change in memory. Setting the state with the same value won't make React re-render our component.
Conclusion
So let's review.
1. When to useState
If you answer no to all of these:
- Is it passed in from a parent via props?
- Can you compute it based on any other state/props in your component?
- Does it remain unchanged over time?
2. Import it
import React, { useState } from 'react'
3. Declare it
const [count, setCount] = useState(0);
4. Set it
setCount((count) => count + 1);
Hopefully this helps. Good luck on your coding journey!
References
- https://react.dev/learn/thinking-in-react#step-3-identify-the-minimal-but-complete-representation-of-ui-state
- https://www.freecodecamp.org/news/react-hooks-fundamentals/#:~:text=React%20Hooks%20are%20simple%20JavaScript,updater%20function%20to%20update%20it.
- https://legacy.reactjs.org/blog/2019/02/06/react-v16.8.0.html
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
- https://react.dev/learn/updating-objects-in-state
Top comments (0)