In React, state refers to mutable data that often changes as a result of user interaction. When the state changes, the UI must be updated to reflect those changes.
The useState
Hook takes the initial state as an argument (in this case, 0
). It returns an array with two elements: the current state (count
) and a function to change the state (setCount
).
The general syntax for employing useState
is:
The useState
Hook returns an array. The bracket syntax [state, setState]
to the left of the equal sign is array destructuring.
If you are using TypeScript, you can specify the type of the state:
For example, the count
state in the above example is a number:
useState
?The useState
is a JavaScript function built into the React library. You must import it before using it.
The useState
function is a “Hook” that lets you add state to function components. You may employ useState
(or any other React Hook) in a function component.
useState
in class components.useState
from regular JavaScript functions.useState
from outside of a function component.useState
(or any React Hooks) inside loops, conditions, or nested functions.Instead, always use useState
at the top level of your React function component.
useState
?Originally, React class components were meant to be stateful components, while function components were stateless. However, this limitation was lifted by the introduction of React Hooks (since React 16.8). Since then, function components can hold state too. When you use Hooks in a function component, React creates an object to live alongside it. In this object, React stores the state (and other metadata) about the component. There is no magic—it’s a technique to allow you to use “state” with functions, a programming construct that is naturally stateless!
useState
In class components, the entire state lives in one (potentially large) object, this.state
. However, with useState
, you can use as many variables as you wish to hold the state in function components.
Each useState
can store one value, and the value can be any JavaScript type—number, boolean, object, array, etc.
When you call useState
, you pass the initial state as an argument. This initial state can be a primitive value (like a number or string), an object, or an array. You can also pass a function that returns the initial state.
In the above example, the initial state is set to the value of localStorage.getItem("count")
or 0
if the value is null
.
The state variable created by useState
always contains the latest value of the state. You should treat it as immutable. This means you should not modify the state directly. Instead, you must use the function returned by useState
to update the state. Only then React will know the state has been updated, and it will re-render the UI.
With useState
, it’s common to name the returned values like foo
and setFoo
, but you can call them whatever you like. If you are from the OOP world, it might help to think about these two as a “getter” and a “setter” for an attribute!
When you update the state using a setter function provided by useState
, you have two primary ways to update the state: directly with a new value or with a function that takes the current state and returns the new state. Here are the two patterns:
Direct update:
Functional update:
While both of these approaches will work in our earlier example, the second approach (functional update) is generally recommended for a few important reasons that we will discuss next.
React may batch multiple state updates for performance reasons. If you use the first approach (setCount(count + 1)
), there is a risk that the count
value you reference might be outdated if multiple updates are batched together. This can lead to unexpected behavior.
For example:
If count
starts at 0, you might expect it to be 3 after this sequence. However, due to batching, it could end up being just 1.
In contrast, the functional update ensures that each update operates on the most recent state:
Here, prevCount
is guaranteed to be the latest state value, and the final state will correctly be 3.
When the new state depends on the previous state, using the functional form avoids bugs and ensures the update is accurate. It’s a best practice to use the functional update form in these scenarios.
Moreover, using the functional update form makes it clear that the new state is derived from the previous state, improving code readability and maintainability. It signals to other developers (and your future self) that the update relies on the current state value.
When updating an array state, you should create a new array with the updated values. You should not mutate the existing array directly. Here is an example:
In the above example, the addTodo
function takes a new todo object and uses the functional update form to add it to the todos
array. It creates a new array by spreading the previous todos and appending the new todo object.
You can use an object as the state.
Potentially, you might want to use a single object to store all the state values related to a particular component. As stated, this was the approach in class components, where the entire state lived in this.state
. With useState
, the recommended approach is to use multiple state variables for different pieces of state. However, if you prefer to use a single object, you can do so.
When updating an object state, you should create a new object with the updated values. You should not mutate the existing object directly. Here is an example:
In the above example, the updateContent
function takes an updated content value and uses the functional update form to update the content
property of the post
object. It creates a new object by spreading the previous post
object and updating the content
property.
The function useState
is a React Hooks. Hooks are functions that let you “hook into” React state and lifecycle features from function components. Hooks do not work inside classes. They were introduced in React 16.8 to make it possible to use state and other React features without writing a class.
We know useState
is a Hook because its name starts with use
. All Hooks follow the same naming convention. If you want to create your own Hooks, you must follow the same convention.
We already explored useState
. The next section will overview the useEffect
Hook. These two functions are bay far the most commonly used Hooks. However, there are other Hooks built into React, and you can create your own Hooks too! Please consult the resources below.