Reputation: 2204
I click the icon 'delete' on the product. I pull out his index and save it in state. Example: select: 1
,index: 1
.
How to set this.setState
to delete an object nested in an array colors
in array products
. Example delete object:
{
a: 'orange'
}
from array colors
in array products
this.state.select
is the item in the products, this.state.index
is color in the item to delete
And how does it look in a real application? Give your products and colors id? I would like it to be dynamic. I click the product, download its index and delete
class App extends Component {
constructor(){
super();
this.state {
products: [
{
colors: [{a:'black'}, {a:'orange'}, {a:'purple'}]
desc: 'gfgfg'
},
{
colors: [{a: 'yellow'}, {a: 'white'}, {a:'gray'}],
desc: 'gfgfgfg'
},
{
colors: [{a: 'pink'}, {a: 'brown'}, {a:'green'}],
desc: 'gfgfgfg'
}
],
select: 1 //example
index: 1 //example
}
}
removeItem = () => {
const { select, index } = this.state;
if(index) {
this.setState({
products: [
...this.state.products[select].colors.slice(0, index),
...this.state.products[select].colors.slice(index + 1),
]
});
}
};
render () {
return (
<div>
<ul>
{
this.state.products
.map((product, index) =>
<Product
key={index}
index={index}
product={product}
/>
)
}
</ul>
<Products
/>
</div>
)
}
}
Upvotes: 3
Views: 2349
Reputation: 16122
You need to pass the remove function to Product
component, in Product
component pass the select and index to removeItem
function.
modify your remove item, to take in two parameters, select
and index
.
removeItem = (select, index) => {
const filtered = this.state.products[select].colors.filter(
(color, i) => i !== index
);
this.setState(prevState => {
return {
select: select,
index: index,
products: [
...prevState.products.slice(0, select),
Object.assign({}, prevState.products[select], { colors: filtered }),
...prevState.products.slice(select + 1)
]
};
});
};
Pass the function as prop to Product
component.
<div>
<ul>
{this.state.products.map((product, index) => (
<Product
key={index}
index={index}
removeItem={this.removeItem}
product={product}
/>
))}
</ul>
</div>
In your product component, pass the index of the color and the select.
<button onClick={() => removeItem(index, i)}>X</button>
DEMO
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
class Product extends React.Component {
render() {
const { product, removeItem, index } = this.props;
return (
<div>
<p>{product.desc}</p>
<ul>
{product.colors.map((color, i) => (
<li>
{color.a} <button onClick={() => removeItem(index, i)}>X</button>
</li>
))}
</ul>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
name: "React",
products: [
{
colors: [{ a: "black" }, { a: "orange" }, { a: "purple" }],
desc: "gfgfg"
},
{
colors: [{ a: "yellow" }, { a: "white" }, { a: "gray" }],
desc: "gfgfgfg"
},
{
colors: [{ a: "pink" }, { a: "brown" }, { a: "green" }],
desc: "gfgfgfg"
}
],
select: 1, //example
index: 1 //example
};
}
removeItem = (select, index) => {
const filtered = this.state.products[select].colors.filter(
(color, i) => i !== index
);
this.setState(prevState => {
return {
select: select,
index: index,
products: [
...prevState.products.slice(0, select),
Object.assign({}, prevState.products[select], { colors: filtered }),
...prevState.products.slice(select + 1)
]
};
});
};
render() {
return (
<div>
<ul>
{this.state.products.map((product, index) => (
<Product
key={index}
index={index}
removeItem={this.removeItem}
product={product}
/>
))}
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
</script>
Upvotes: 1
Reputation: 8589
Just use Array.filter()
to create a new array not containing the specific element. So your new color array for that desc is:
this.state.products[select].colors.filter( color => color.a !== 'orange' )
This keeps all the colors where a
is not orange.
Keep in mind that arrays are zero-based, so your select
and index
should both start at 0.
If you do not want to store the actual indexes, use the desc instead.
So if select
would be gfgfg
instead of the array index, you could do:
const state = {
products: [
{
colors: [{a:'black'}, {a:'orange'}, {a:'purple'}],
desc: 'gfgfg'
},
{
colors: [{a: 'yellow'}, {a: 'white'}, {a:'gray'}],
desc: 'gfgfgfg'
},
{
colors: [{a: 'pink'}, {a: 'brown'}, {a:'green'}],
desc: 'gfgfgfg'
}
],
selected_product: 'gfgfg',
color: 'orange'
};
const setState = update => Object.assign( state, update );
console.log( 'before update' );
console.log( JSON.stringify( state.products[0] ));
setState({
products: state.products.map( product => {
if ( product.desc === state.selected_product ) {
product.colors = product.colors.filter( color => color.a !== state.color );
}
return product;
})
});
console.log( 'after update' );
console.log( JSON.stringify( state.products[0] ));
Same logic can obviously be done using the indexes, but that might result in longer code. Might have to update some of the code if everything has to be fully immutable.
Upvotes: 0