Reputation: 87
I'm mapping an array in the state to build dropdowns dynamically. I have two working methods to add and remove values in the array. When I remove and add values to the array I want the UI elements to also update as the state changes. Addition works but deletion fails every time. I have confirmed the array in the state is being changed correctly but I can only ever delete the newest component instead of a specific one. Thanks for your help.
//
handleToggle() {
return this.state.AdditionQueryArray.map((array, index) => {
let key = array.key;
return (
<div>
<Select
onChange={(e) => this.AdditionalOperatorHandleChange(e, key)}
options={this.state.OperatorOptions}
placeholder="Select Operator"
menuPortalTarget={document.body}
menuPosition={"fixed"}
/>
<button onClick={() => this.deleteAdditonalQuery(index)}>
Delete
</button>
{this.forceUpdate}
</div>
);
});
}
createAdditionalQuery() {
const state = this.state;
let key = Math.random().toString(36).substring(7);
var copyArr = [...this.state.AdditionQueryArray];
copyArr.push({
key: key,
field: "fieldDefault",
property: "propertyDefault",
PropValue: "Propvalue",
});
this.setState({
AdditionQueryArray: copyArr,
});
}
deleteAdditonalQuery(indexVal) {
var state = this.state;
var copyArr = [...this.state.AdditionQueryArray];
if (indexVal > -1) {
copyArr.splice(indexVal, 1);
}
this.setState({
AdditionQueryArray: copyArr,
});
}
render() {
return (
<div>
<button onClick={this.createAdditionalQuery}>Add Query </button>
{this.handleToggle()}
</div>
);
}
////
Upvotes: 0
Views: 392
Reputation: 202638
Shallow copy and array.splice
is interesting way to remove an element from an array by index. I suggest using array.filter
instead, it's much more clean. I suggest always using functional state updates when updated arrays stored in state, especially when used in callbacks attached in loops. This avoids any stale state enclosures.
deleteAdditonalQuery(indexVal) {
this.setState(prevState => ({
AdditionQueryArray: prevState.AdditionQueryArray.filter(
(el, index) => index !== indexVal
),
}));
}
Similarly in the add handler, use a functional state update.
createAdditionalQuery() {
this.setState(prevState => ({
AdditionQueryArray: prevState.AdditionQueryArray.concat({
key: Math.random().toString(36).substring(7),
field: "fieldDefault",
property: "propertyDefault",
PropValue: "Propvalue",
}),
}));
}
In handleToggle
remove the "dead" force update code, it shouldn't be necessary. It's not being invoked anyway. Don't forget to add a React key to the outermost element being mapped.
handleToggle() {
return this.state.AdditionQueryArray.map((array, index) => {
const key = array.key;
return (
<div key={key}> // <-- add React key!
<Select
onChange={(e) => this.AdditionalOperatorHandleChange(e, key)}
options={this.state.OperatorOptions}
placeholder="Select Operator"
menuPortalTarget={document.body}
menuPosition={"fixed"}
/>
<button onClick={() => this.deleteAdditonalQuery(index)}>
Delete
</button>
</div>
);
});
}
Upvotes: 1