Reputation: 1950
I am trying to (without mutating state) update a value that is nested.
The result should go from:
[{ name: "hello", id:20, genre: [{ name: 'baz', id: 2 }, { name: 'foo', id: 200 }] }, { name: "hi", id:12, genre: [] }]
to
[{ name: "hello", id:20, genre: [{ name: 'test', id: 2 }, { name: 'foo', id: 200 }] }, { name: "hi", id:12, genre: [] }]
I have located the index
of the item I want to update- nestedIndex
. Although, matching using ID
would also be find (if index
is not a good idea).
I attempted to it here:
return item.name === x.name ? { ...item, name: e.target.value, genre[nestedIndex].name: 'test' } : item
How do I update a nested item in setState?
Here is a working example: https://codesandbox.io/s/rl6yoyz1rm
Here is my full code:
state = {
search: "",
items: [{ name: "hello", id:20, genre: [{ name: 'baz', id: 2 }, { name: 'foo', id: 200 }] }, { name: "hi", id:12, genre: [] }]
};
onChange(e, x) {
const { items } = this.state
const index = items.findIndex(itm => itm.name === x.name)
const nestedIndex = [items[index]].map(e => e.genre).pop().findIndex(itm => itm.id === 2)
this.setState({
items: items.map(item => {
return item.name === x.name ? { ...item, name: e.target.value } : item
})
});
}
render() {
const { items } = this.state;
return (
<div>
{items.map((x) => {
return (
<div>
{" "}
{x.name}
{x.genre.map((itm) => {
return <i> {itm.name}</i>;
})}
<input onChange={e => this.onChange(e, x)} type="text" />
</div>
);
})}
</div>
);
}
}
Upvotes: 0
Views: 50
Reputation: 7424
Since you are updating an array which also happens to have another nested array, you can map through items and spread props as you need.
class App extends React.Component {
constructor() {
super()
this.state = {
items: [{
name: 'hello',
id: 20,
genre: [{ name: 'baz', id: 2 }, { name: 'foo', id: 200 }],
},
{ name: 'hi', id: 12, genre: [] },]
}
this.onChange = this.onChange.bind(this)
}
onChange(event, clickedItem) {
const { items } = this.state
const index = items.findIndex(item => item.name === clickedItem.name)
const nestedIndex = items[index].genre.findIndex(genre => genre.id === 2)
const { value } = event.target
this.setState(prevState => ({
items: prevState.items.map((item, itemIndex) => {
if (index !== itemIndex) {
return item
}
return {
...item,
genre: item.genre.map((genre, gIndex) => {
if (gIndex !== nestedIndex) {
return genre
}
return {
...genre,
name: value,
}
})
}
})
}))
}
render() {
const { items } = this.state;
return (
<div>
{items.map((x) => {
return (
<div>
{" "}
{x.name}
{x.genre.map((itm) => {
return <i> {itm.name}</i>;
})}
<input onChange={e => this.onChange(e, x)} type="text" />
</div>
);
})}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Upvotes: 1