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
  • 18,570
  • 6
  • 30
  • 49
Kaiser91
  • 323
  • 3
  • 15
  • 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
  • 18,570
  • 6
  • 30
  • 49
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
  • 1,884
  • 10
  • 16
4

USE

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

INSTEAD OF

setColors({...colors, colors: { colorB: 'WHITE'}})
Simon Gomes
  • 363
  • 1
  • 4
  • 17
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,125
  • 2
  • 22
  • 32
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
  • 7,353
  • 4
  • 33
  • 67
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,507
  • 14
  • 22