Reputation: 155
Actually I have a list of elements, that have to store into an array as react state.
const [data, setData] = useState([{"name": "joy", "age": 25}, {"name": "tom", "age": 41}]);
Somehow I need to update only a particular object, May be name or age.
I am doing in such way. But It seems not good.
setData(prevState => {
let obj = prevState.find(o => anycondition);
if(obj !== undefined) {
obj.name = "Demo";
}
return [...prevState];
})
is there any other method to update only object from state array using React Hooks?
Upvotes: 0
Views: 2712
Reputation: 202836
Doing this is a state mutation!!
setData(prevState => {
let obj = prevState.find(o => anycondition);
if(obj !== undefined) {
obj.name = "Demo"; // <-- state mutation
}
return [...prevState];
})
Should always shallowly copy current state that is being updated
setData(prevState => {
return prevState.map(el => <condition> ? { // <-- map state to new array
...el, // <-- copy element
name: "Demo", // <-- write new property
} : el);
})
If you need to do any calculations within the map callback, give the callback a normal function body and add any logic needed.
setData(prevState => {
return prevState.map(el => { // <-- map state to new array
// any mapping logic
...
if (<condition>) {
// any other logic
...
return {
...el, // <-- copy element
name: "Demo", // <-- write new property
}
} else {
return el;
}
});
})
Upvotes: 4
Reputation: 1297
try this way ;)
function mergeState(state, payload) {
return { ...state, ...payload }
}
const [state, dispatch] = useReducer(mergeState, {
name: '',
age: 0,
data: [{"name": "joy", "age": 25}, {"name": "tom", "age": 41}],
})
// get the data
const data = state.data.map(item => {
if(obj !== undefined){
obj.name = "Demo";
}
return item
})
// update
dispatch({data})
Upvotes: 0
Reputation: 2641
To handle this with more control you can add an id prop to each object.
If you want to change/modify an specific object, just do:
const [data, setData] = useState([
{
id: 1,
name: "joy",
age: 25
},
{
id: 2,
name: "tom",
age: 41
}
]);
const updateItem = (id, attributes) => {
const index = data.findIndex(item => item.id === id);
if (index === -1)
return;
setData(
[
...data.slice(0, index),
Object.assign({}, data[index], attributes),
...data.slice(index + 1)
]
);
}
// You can update the second item as follows
updateItem(2, { age: 50 })
Upvotes: 0
Reputation: 558
Maybe you want something like this?
here you will loop only once and update data which you want
changeHandler = event => {
const [name, value] = event.target.name
setData(prevState => prevState.map(item => {
if (anycondition) {
return {
...item,
[name]: value
}
}
return item
}))
}
If you want to get some id from input too, you can pass it with data sets like here data-id={1}
And then get it from an event like this const id = e.target.dataset.id;
in changeHandler
function
<input
type="text"
name="name"
data-id={1}
value={this.state.data.name.fname}
onChange={this.changeHandler}
/>
Upvotes: 0