DEV Community

Cover image for Different ways of setting State in React
Jess Alejo
Jess Alejo

Posted on

Different ways of setting State in React

In React, the useState hook is used to manage state in functional components. There are several ways to set or update the value of a state variable using useState. Below are different methods and examples to demonstrate how you can set or update state values.

1. Setting Initial State

The most basic way to initialize state is by passing an initial value to useState.

import React, { useState } from 'react';

function App() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(10)}>Set Count to 10</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • Here, useState(0) initializes the count state to 0.
  • The setCount(10) function sets the count state to 10 when the button is clicked.

2. Updating State Based on the Previous State

When updating state based on the previous state, it's important to use the functional form of the state setter function. This ensures that you're working with the most up-to-date state, especially in asynchronous scenarios.

import React, { useState } from 'react';

function App() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount((prevCount) => prevCount + 1); // Functional update
  };

  const decrement = () => {
    setCount((prevCount) => prevCount - 1); // Functional update
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • In this example, setCount((prevCount) => prevCount + 1) updates the count state based on its previous value.
  • This is particularly useful when multiple state updates might happen in quick succession (e.g., inside loops or asynchronous functions).

3. Updating Complex State (Objects or Arrays)

When dealing with objects or arrays, you need to be careful because React's state updates are shallow. This means that you should always create a new object or array when updating state to ensure React detects the change.

Example with Objects:

import React, { useState } from 'react';

function App() {
  const [user, setUser] = useState({ name: 'John', age: 30 });

  const updateName = () => {
    setUser((prevUser) => ({ ...prevUser, name: 'Jane' })); // Spread operator to copy previous state
  };

  const updateAge = () => {
    setUser((prevUser) => ({ ...prevUser, age: 35 })); // Spread operator to copy previous state
  };

  return (
    <div>
      <p>Name: {user.name}, Age: {user.age}</p>
      <button onClick={updateName}>Change Name to Jane</button>
      <button onClick={updateAge}>Change Age to 35</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • Here, setUser is used to update the user object.
  • We use the spread operator (...) to create a shallow copy of the previous state and then override specific properties (name or age).

Example with Arrays:

import React, { useState } from 'react';

function App() {
  const [items, setItems] = useState([1, 2, 3]);

  const addItem = () => {
    setItems((prevItems) => [...prevItems, prevItems.length + 1]); // Add a new item
  };

  const removeItem = () => {
    setItems((prevItems) => prevItems.slice(0, -1)); // Remove the last item
  };

  return (
    <div>
      <p>Items: {items.join(', ')}</p>
      <button onClick={addItem}>Add Item</button>
      <button onClick={removeItem}>Remove Item</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • In this example, setItems is used to update the items array.
  • To add an item, we spread the previous array and append a new element.
  • To remove an item, we use slice to create a new array without the last element.

4. Batching Multiple State Updates

React automatically batches state updates for performance optimization. However, if you want to ensure multiple state updates are batched together, you can use functional updates.

import React, { useState } from 'react';

function App() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState('Initial Message');

  const updateBoth = () => {
    setCount((prevCount) => prevCount + 1);
    setMessage((prevMessage) => `${prevMessage} Updated`);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <p>Message: {message}</p>
      <button onClick={updateBoth}>Update Both</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • In this example, both setCount and setMessage are called in sequence.
  • React will batch these updates together, ensuring that the component re-renders only once.

5. Lazy Initialization of State

You can pass a function to useState if the initial state requires some computation or is expensive to calculate. This function will only run once during the initial render.

import React, { useState } from 'react';

function App() {
  const computeInitialValue = () => {
    console.log('Computing initial value...');
    return 42;
  };

  const [value, setValue] = useState(() => computeInitialValue());

  return (
    <div>
      <p>Value: {value}</p>
      <button onClick={() => setValue(100)}>Set Value to 100</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • Here, computeInitialValue is only called once during the initial render, thanks to the lazy initialization pattern.
  • This is useful when the initial state calculation is expensive or involves side effects.

6. Resetting State to Initial Value

Sometimes you may want to reset the state to its initial value. You can do this by storing the initial value in a variable and using it to reset the state.

import React, { useState } from 'react';

function App() {
  const initialValue = 0;
  const [count, setCount] = useState(initialValue);

  const resetCount = () => {
    setCount(initialValue);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <button onClick={resetCount}>Reset</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • In this example, initialValue is stored in a variable, and resetCount resets the count state to 0.

Summary of Different Ways to Set State:

  1. Directly setting a new value: setState(newValue)
  2. Updating based on the previous state: setState((prevState) => newState)
  3. Updating complex state (objects/arrays): Use the spread operator (...) to create a new object or array.
  4. Batching multiple state updates: React automatically batches updates, but you can use functional updates to ensure consistency.
  5. Lazy initialization: Pass a function to useState for expensive initial state calculations.
  6. Resetting state: Store the initial value in a variable and reset the state using that value.

These techniques give you flexibility in managing state in React applications, whether you're dealing with simple values, complex objects, or arrays.

Top comments (2)

Collapse
 
pengeszikra profile image
Peter Vivo

Why don't like useReducer for complex solution?

Collapse
 
jessalejo profile image
Jess Alejo

Thanks for the reminder! I’m still getting the hang of React since I’m pretty new to it, and I’ve already forgotten some of what I learned a while back. But don’t worry, I’ll catch up and be there soon! 😊