2

Would like to know if there is a way to update nested object states in React using useState()

import React, {useState} from 'react'

const MyComp = () => {

  const [colors, setColors] = useState({colorA: 'RED', colorB: 'PURPLE'});

  return (
    <div>
       <span>{colors.colorB}</span>
       <button onClick={() => setColors({...colors, colors: { colorB: 'WHITE'}})}>CLICK ME</button>
    </div>
  )
}


export default MyComp;

I was thinking to use useReducer() but I read that It's normally use for more complex states and maybe there is a solution for this case just using useState()

Any ideas?

Thx in advance

Dupocas
  • 20,285
  • 6
  • 38
  • 56
Kaiser91
  • 333
  • 6
  • 17
  • Does this answer your question? [React Hooks useState() with Object](https://stackoverflow.com/questions/54150783/react-hooks-usestate-with-object) – PEPEGA Dec 03 '19 at 11:33

6 Answers6

4

colors already is the whole object, you don't need to declare as a property.

spread the original object and override colorB

() => setColors({...colors, colorB: 'WHITE'}) 
Dupocas
  • 20,285
  • 6
  • 38
  • 56
4

You are updating the state in a wrong way. Change your button statement to below,

<button onClick={() => setColors({...colors, colorB: 'WHITE'})}>CLICK ME</button>
Gangadhar Gandi
  • 2,162
  • 12
  • 19
4

USE

setColors({...colors, colorB: 'WHITE'})

INSTEAD OF

setColors({...colors, colors: { colorB: 'WHITE'}})
Simon Gomes
  • 383
  • 1
  • 5
  • 18
3

It's better to use functional form of setState for this, since the next state value depends on the current value of the state:

 return (
    <div>
      <span>{colors.colorB}</span>
      <button
        onClick={() => setColors(currentColors => ({ ...currentColors, colorB: "WHITE" }))}
      >
        CLICK ME
      </button>
    </div>
  );
Clarity
  • 10,730
  • 2
  • 25
  • 35
2

Since you have already done the spread, it will have the property colorB, you just need to update with new value

const handleButtonClick = () => {
    setColors({ ...colors, colorB: "WHITE" });
  };

making it into a function will be more readable.

Code

import React, { useState } from "react";
import ReactDOM from "react-dom";

const MyComp = () => {
  const [colors, setColors] = useState({ colorA: "RED", colorB: "PURPLE" });

  const handleButtonClick = () => {
    setColors({ ...colors, colorB: "WHITE" });
  };

  return (
    <div>
      <span>{colors.colorB}</span>
      <button onClick={handleButtonClick}>CLICK ME</button>
    </div>
  );
};

export default MyComp;

const rootElement = document.getElementById("root");
ReactDOM.render(<MyComp />, rootElement);

Working Codepen

Learner
  • 8,379
  • 7
  • 44
  • 82
0

There was a minor syntax error in the statement

 const App = () => {


  const [colors, setColors] = useState({ colorA: 'RED', colorB: 'PURPLE' });

  return (
    <div>
      <span>{colors.colorB}</span>
      <button onClick={
        () =>
          setColors(
            { ...colors,colorB: 'WHITE' }
          )
      }>CLICK ME</button>
    </div>
  )
}
Snivio
  • 1,741
  • 1
  • 17
  • 25