'react-select doesn't keep indexes on manipulated arrays
In an array of react-selects, any input before the last one will break indexing for the following ones. I know about uuid for key (which is not recommended) and also about Math.floor(Math.random() * 10000) for key. But I still can't get this to work.
The key generated with Math.floor(Math.random() * 10000) breaks the input: you can't populate anything into the field.
It's an indexing problem and I believe it's a problem from within the plugin. I need to clarify this isn't the issue hopefully.
I've created a codesandbox with Math.floor(Math.random() * 10000) as key so you'd see.
https://codesandbox.io/s/codesandboxer-example-forked-dcvdj?file=/example.tsx
Add on at least one input and try to populate. It won't let you.
Put index in key and you'll see you can populate, but when you try to delete it, the value stays the same and instead the one under that one gets deleted (indexing issue, I know). This is because when state is updated, map will run again and will reindex the list once again.
Solution 1:[1]
One solution would be to reference you AsyncSelect values into an array like so:
state = {
inputValue: "",
fieldsArr: [],
values: []
};
Consequently your render() function would look like:
render() {
return (
<div>
<pre>inputValue: "{this.state.inputValue}"</pre>
{this.state.fieldsArr.map((item, index) => (
<div key={index}>
<span>{item}</span>
<AsyncSelect
cacheOptions
loadOptions={this.loadOptions}
defaultOptions
value={this.state.values[index]} // <--- This will reference your state value
onChange={(e) => this.handleChange(e, index)}
onInputChange={this.handleInputChange}
/>
<button onClick={() => this.handleDelete(index)}>delete</button>
</div>
))}
<button onClick={this.handleAdd}>add</button>
</div>
);
}
Then you will add an handleChange callback to handle the AsyncSelect onChange event.
handleChange(el, index) {
let vals = this.state.values;
vals[index] = el;
this.setState((prev) => ({ ...prev, values: vals }));
}
And finally edit the handleDelete and handleAdd functions accordigly:
handleAdd = () => {
let newArr = this.state.fieldsArr;
let values = this.state.values;
newArr.push(this.state.fieldsArr.length + 1);
values.push("");
this.setState((prev) => ({ ...prev, fieldsArr: newArr }));
};
handleDelete = (index) => {
let newArr = this.state.fieldsArr;
let values = this.state.values;
newArr.splice(index, 1);
values.splice(index, 1);
this.setState((prev) => ({ ...prev, fieldsArr: newArr, values }));
};
Solution 2:[2]
My solution was to create a counter, add to that counter on add field, then on delete using indexOf item to delete.
https://codesandbox.io/s/codesandboxer-example-forked-dcvdj?file=/example.tsx
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Antonio Della Fortuna |
| Solution 2 | Manny Alvarado |
