React useState hook: Complete guide and tutorial

Published on May 8, 2025

React useState hook: Complete guide and tutorial

The React useState hook adds a state variable to a function component. Setting a state variable gives your component the ability to remember things across page re-renders, so that data can be stored and the component can be updated when the data changes. This guide explains state in React and how to use the useState hook, with working code examples.

What is the React useState hook?

The React JavaScript library provides a set of tools for building user interfaces using components. Each component has a lifecycle in which it is mounted (created and added to the React virtual DOM), updated (re-rendered, which can occur multiple times whenever state or component prop values change, and does not involve a page refresh), and unmounted (destroyed and removed from the virtual DOM). Hooks are functions that tap into this lifecycle so that you can perform actions at different points. React comes with several built-in hooks, and you can also write your own custom hooks.

useState is one of the hooks that are built into the React library. It is concerned with the management of state: the ability for your React components to store and recall data across their lifecycle.

useState creates a state variable for storing this data in memory. State data is managed internally by React and does not survive a browser refresh. Multiple useState hooks can be added to a component to track the value of multiple variables, and when any state variable changes, React automatically triggers a re-render of the component. 

You can store objects in a state variable: for example, rather than using multiple useState hooks to manage the state for an entire HTML form, you can store those values in an object that models the form.

What does the useState hook do? What is the benefit?

You don’t need state for simple web pages that only display data as they are unconcerned with what the user is doing. Most modern websites and apps, however — even those that may seem to lack interactivity —  require state to provide the reactive, engaging experiences users now expect. 

Basic functions like remembering a user's preferences (dark or light mode?), pagination, sorting and filtering selections (e.g., in an ecommerce listing), and client-side form validation rely on your code being able to maintain state. You can also use state to perform background tasks like displaying data without having to reload it for each render. 

With the useState hook, React makes state management a straightforward process compared to manually implementing this functionality yourself. React hooks also work with pre-built component libraries.

React also includes the useEffect, useReducer, and useContext hooks to help you effectively manage state for reactive apps, with each serving a different purpose.

useState vs. useEffect

The React useEffect hook can be used in conjunction with useState to keep local state data in sync with an external source such as an API. This significantly reduces the work required to build frontend applications that must continuously load data from a backend server, like a multiplayer game or chat application. 

useEffect runs just after the component renders, making it suitable for initializing any data that shouldn't block rendering (e.g., setting state, setting up event listeners). You can also use it to return a cleanup function that you can use to tidy up on unmount (e.g., clearing timers).

useState vs. useReducer

A reducer is a single function that consolidates all of the state logic for a component (by taking the current state, responding to a specified action, and returning an updated state). The useReducer hook is an alternative to useState that sets the reducer function that will handle the state for the React component.

useState vs. useContext

In React, a context allows you to pass data from one component to all components under it, rather than having to pass it from each component down to the next using props (helping you avoid prop drilling). The useContext hook allows you to read the value of the nearest matching context of a parent component. It can be used separately or alongside the useState hook as they are separate in purpose.

How does the useState React hook work?

When adding state to a component using the React useState hook, you must define the name of the state variable and the name of the setState function that will be used to set/update it (as you are defining these, you choose what to name them). When called, the function to update the state will trigger a re-render if it changes the value of the state variable, determined by React using a shallow comparison.

Below is an example React component for counting sheep that uses useState to create a sheepCount state variable with a setSheepCount function to update it. Note that useState accepts a value to initialize the state variable with, in this case 0.

When clicked, the HTML button calls the handleButtonClick() function, which increments the current sheepCount value and passes it to setSheepCount to update the state variable. Throughout the example code, the sheepCount variable can be used to read its current value from the state.

How does the useState React hook work?

State variables created using the React useState hook can contain any type of data, from primitives such as strings and numbers to complex nested objects. Note also that state variables are scoped to the component they are declared in.

How to use the React useState hook to store and nested objects using useState

Here is a more complex example that demonstrates how to use the React useState hook in a functional application. You can view all of the useState code examples on this page in this code sandbox to see how they behave when they are running.

The below React component uses the useState hook to save a list of shopping list items as objects in an array. It uses multiple calls to the React useState hook to track different elements: one state variable tracks the state of the shoppingListItems, while the itemName and itemQuantity form values have their own state variables that are reset when the form is submitted.

When handling arrays and objects with useState, it is critical that you never update a value within an array or object — you must always replace it using the setState function.

React useState hook and state management best practices and troubleshooting

As with any programming language feature or development tool, incorrectly using the React useState hook can lead to errors, unexpected behavior, or degraded performance.

The React useState hook must be called at the top level of function components

The useState hook can be used in function components to add state to them, and does not support class components. Hooks must be called at the top level of function components (never inside loops or conditionals!) so that they are always called in the same order, allowing React to maintain a consistent state. 

Avoid infinite loops

You should also be careful when structuring your code so that you don't create infinite loops when setting state variables, or you will receive the “Too many re-renders” error when a render triggers another set state, which will in turn trigger another render. This commonly happens when setting state for a dependency you have in a useEffect.

As mentioned before, it's vital to ensure that you do not mutate state values directly, and instead use their associated setState function. React tracks state by object references, so if you mutate directly, the reference stays the same and React is unable to track it.

Be aware of how JavaScript compares and copies arrays and objects

If updating an array, you can use the JavaScript spread syntax (...) to duplicate the array and then append, update, or remove values before using the copy to replace the state variable. 

If updating multi-dimensional objects or arrays, the spread syntax is insufficient (as it only copies one level deep). A common workaround to this is to use JavaScript’s JSON.parse and JSON.stringify methods to create a deep copy of the array or object, for example:

let shoppingListCopy = JSON.parse(JSON.stringify(shoppingList))

This method does struggle with dates and undefined values, so it may be preferable to use the cloneDeep function from the lodash utility library to accurately clone JavaScript objects if they contain anything more than strings and numbers.

Understand how React component lifecycle and hooks work

Using a setState function does not update the state variable for within the current render! This is a gotcha that many new React developers encounter: as useState is a lifecycle hook, values updated using setState will not change until the next render. To sidestep this problem, you can create a variable within the current function to hold the state value, modify and use it in the current render, and then finally set it for the next state once it is finalized.

Another common useState pitfall is that initializers run twice when running in React's strict mode. This is intentional (and only happens in development), and can help ensure that your code is correct, as the initializer running twice should not produce unexpected values if you are properly replacing state variables rather than mutating them directly. As mentioned before, directly mutating state variables should be avoided, and is a mistake that commonly causes frustration, as it means the rendered variable may not update.

Prioritize your users

You should also consider performance and user experience when designing and implementing state management for your React app. Lazy initialization can help your app load faster while computationally heavy tasks for the initial state are completed. 

You can also implement React Suspense to only load components when they are ready for display (it operates completely separately to setState and other hooks, but can improve the user experience by hiding components until they are ready).

Leverage Reacts nuances rather than letting them become a troubleshooting issue

As the state for each instance of a component is isolated to that instance, recreating a component will “reset” it to its default state. This means that if you want to reset the state of a component, you can do this by destroying and recreating it, or by recreating it as a result of conditional rendering. Another way to reset the state of a component is by changing its key. Unintentionally performing these actions can cause the state of a component to unexpectedly reset or not persist, so make sure that you do not recreate components you need to maintain state for, and ensure that you're updating the state variable at the correct point in the component’s lifecycle.

While you can store functions in state variables, you cannot pass the function to the useState hook directly or React will assume it is an initializer function. To prevent this, you need to add a ()=> to wrap these functions in another function.

If you are encountering race conditions (where state updates are happening rapidly, and as a result updates may reference old data), but your state isn't complex enough to justify using useReducer, you can pass a function as an argument to the setState update function for a state variable so that it always gets the most recent state, no matter what order the updates have been processed in.

If you're bootstrapping a new React project to give the useState hook and state management a try, check out our Contentful React Starter. It includes everything you need to start building a React app with Contentful.

Keeping your front ends in sync with your back end

Websites and apps that rely solely on frontend code are limited in scope. Users expect high interactivity reinforced by personalized experiences and dynamic content that cannot be pre-baked into a digital product.

By supporting your React front end with Contentful, you can publish fresh content to your websites, apps, billboards, and other channels with a click. Content curation is handled in our flexible online studio, which you can customize to fit your creative process. You can connect your React apps to Contentful using our REST and GraphQL APIs and JavaScript SDKs, and keep them in sync with React’s useState and useEffect hooks for live experiences.

Contentful doesn't just reduce the backend code you need to write and maintain: it serves your structured text, video, and other media content from our high-speed global CDN, providing high performance while also eliminating the need for additional scalable infrastructure for your projects. This leaves you free to focus on building and improving your core experience for your users.

Subscribe for updates

Build better digital experiences with Contentful updates direct to your inbox.

Meet the authors

David Fateh

David Fateh

Software Engineer

Contentful

David Fateh is a software engineer with a penchant for web development. He helped build the Contentful App Framework and now works with developers that want to take advantage of it.

Related articles

This guide will show you how to create a Next.js application using App Router to fetch knowledge base articles from Contentful via React Server Components.
Guides

How to Integrate Contentful and Next.js App Router

December 13, 2023

Learn React routing with this comprehensive guide! Discover key concepts, explore tools like React Router, and see how to build navigation for your React apps.
Guides

Mastering React routing: A guide to routing in React

January 20, 2025

This tutorial demonstrates how to use SVG images in React, including code examples of how to import SVG into React using several different tools and methods.
Guides

How to use SVG in React: 7 ways to import SVG images (with examples)

October 31, 2024

Contentful Logo 2.5 Dark

Ready to start building?

Put everything you learned into action. Create and publish your content with Contentful — no credit card required.

Get started