React hooks: How do I update state on a nested object with useState()?

codemon picture codemon · Jun 28, 2019 · Viewed 16k times · Source

I have a component that receives a prop that looks like this:

const styles = {
    font: {
        size: {
            value: '22',
            unit: 'px'
        },
        weight: 'bold',
        color: '#663300',
        family: 'arial',
        align: 'center'
    }
};

I'm trying to update the align property, but when I try to update the object, I wind up replacing the whole object with just the align property.

this is how I'm updating it:

const { ...styling } = styles;
const [style, setStyle] = useState(styling);

return (
        <RadioButtonGroup
            onChange={(event) => {
                setStyle({ ...style, font: { align: event.target.value } });
                console.log(style);
            }}
        />);

When I console.log style I just get {"font":{"align":"left"}} back. I expected to see the whole object with the updated value for align. I'm new to destructuring so what am I doing wrong here?

Answer

Shubham Khatri picture Shubham Khatri · Jun 28, 2019

You need to use spread syntax to copy the font object properties too. Also while trying to update current state based on previous, use the callback pattern

<RadioButtonGroup
  onChange={(event) => { 
    setStyle(prevStyle => ({
        ...prevStyle,
        font: { ...prevStyle.font, align: event.target.value }
    }));
    console.log(style);
  }}
/>