Kevin.a
Kevin.a

Reputation: 4296

Change state without overriding other values in react

I am trying to change the state of my app without overriding the values that haven't changed. I am doing so using the spread operator, but something is going wrong.

Here is my base state : useState({data : [{name : undefined , project : []}] });

With setState i want to just add names but keep the project array empty since it didn't change.

setManager(prevState => ({...prevState , data : res.data}))

After performing setState the new state looks like this :

[
    {name: "John doe"},
    {name: "Jane Doe"}
]

as you can see the default state is completely overridden.

res.data looks like this by the way :

[
  {name: "john doe"},
  {name: "jane doe"}
] 

Upvotes: 0

Views: 1318

Answers (3)

xadm
xadm

Reputation: 8418

By setManager(prevState => ({...prevState , data : res.data})) you're simply overriding your earier 'main' data property.

data is an array, new values are in array ... simply concat them

setManager(prevState => ({...prevState , 
  data : prevState.data.concat( res.data )
}))

After that you should have

[  
  {name: undefined , project : []},  
  {name: "john doe"},
  {name: "jane doe"}
] 

... but probably you wanted to manage names and project separately:

const [manager, setManager] = useState({
  data: { 
    name: undefined, 
    project: []
  }
});

... or even

const [manager, setManager] = useState({
  name: undefined, 
  project: []
});

This way you don't need to 'address' this data with 'intermediatory' .data

<Component names={manager.name} />

... not by {manager.data.name}.

Of course updating only name needs different code

setManager(prevState => ({
  ...prevState, 
  name : prevState.name.concat( res.data )
}))
  • ...prevState prevents deleting project property
  • name should be initialized with [], not undefined
  • conditional rendering can be done with `{!manager.name.lenght && ... }

If you have separate states 'slices' then no need to use one common state, use many useState declarations.

Upvotes: 2

keikai
keikai

Reputation: 15146

You inited your state with an Array, not an Object, that's the reason for the behavior.

Change this from

useState({data : [{name : undefined , project : []}] });

to

useState({data : {name : undefined , project : []} });

Upvotes: 1

Łukasz Jagodziński
Łukasz Jagodziński

Reputation: 3079

Probably what you need is:

const [manager, setManager] = useState({
  data: [{ name: undefined, project: [] }]
});

setManager(prevState => ({
  data: prevState.data.map((item, index) => ({ ...item, ...res.data[index] }))
}));

However, if you're just storing an array of "items", then your state should look more like:

const [manager, setManager] = useState([{ name: undefined, project: [] }]);

setManager(prevState =>
  prevState.data.map((item, index) => ({ ...item, ...res.data[index] }))
);

Also, the way how you're gonna merge prev and incoming data depends on many things and maybe you need some more sophisticated way of storing state.

Upvotes: 1

Related Questions