javascript - Hur uppdaterar jag states `onChange` i en array av objekt i React Hooks
Jag har hämtat data som lagrats med useState i en array av objekt, datan skickades sedan ut i formulärfält. Och nu vill jag kunna uppdatera fälten (state) medan jag skriver.
Jag har sett exempel på folk som uppdaterar tillståndet för en egenskap i en array, men aldrig för tillstånd i en array av objekt, så jag vet inte hur man gör det. Jag har fått indexet för objektet skickat till callback-funktionen men jag visste inte hur man uppdaterar tillståndet med det.
// sample data structure
const data = [
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
]
const [data, setData] = useState([]);
const updateFieldChanged = index => e => {
console.log('index: ' + index);
console.log('property name: '+ e.target.name);
setData() // ??
}
return (
<React.Fragment>
{data.map((data, index) => {
<li key={data.name}>
<input type="text" name="name" value={data.name} onChange={updateFieldChanged(index)} />
</li>
})}
</React.Fragment>
)
Svar #1
Här är hur du gör det:
// sample data structure
/* const data = [
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
] */ // make sure to set the default value in the useState call (I already fixed it)
const [data, setData] = useState([
{
id: 1,
name: 'john',
gender: 'm'
}
{
id: 2,
name: 'mary',
gender: 'f'
}
]);
const updateFieldChanged = index => e => {
console.log('index: ' + index);
console.log('property name: '+ e.target.name);
let newArr = [...data]; // copying the old datas array
// a deep copy is not needed as we are overriding the whole object below, and not setting a property of it. this does not mutate the state.
newArr[index] = e.target.value; // replace e.target.value with whatever you want to change it to
setData(newArr);
}
return (
<React.Fragment>
{data.map((datum, index) => {
<li key={datum.name}>
<input type="text" name="name" value={datum.name} onChange={updateFieldChanged(index)} />
</li>
})}
</React.Fragment>
)
Svar #2
Det accepterade svaret leder utvecklaren in i betydande risk att de kommer att förändra källsekvensen, som bevittnat i kommentarer:
let newArr = [...data];
// oops! newArr[index] is in both newArr and data
// this might cause nasty bugs in React.
newArr[index][propertyName] = e.target.value;
Detta kommer att innebära att React, i vissa fall, inte plockar upp och renderar ändringarna.
Det idiomatiska sättet att göra detta är genom att mappa din gamla array till en ny, och byta ut det du vill ändra mot ett uppdaterat objekt längs vägen.
setData(
data.map(item =>
item.id === index
? {...item, someProp : "changed", someOtherProp: 42}
: item
))
Svar #3
setDatas(datas=>({
...datas,
[index]: e.target.value
}))
med index som målposition och e.target.value som det nya värdet
