我在一个react js应用程序中有一个元素列表。
import "./styles.css";
import React from 'react';
const carsData = [
{name: "first car", id: 1, meta: [{id:1, title:'first meta'}]},
{name: "second car", id: 2, meta: [{id:2, title:'second meta'}]},
{name: "third car", id: 3, meta: [{id:4, title:'last meta'}]},
]
export default function App({cars = carsData}) {
const [carsState, setCarsState] = React.useState(cars)
const newItem = {name: "first car", id: 1, meta: [{id:10, title:'added meta'}]}
const click = () => {
setCarsState([...carsState, newItem])
}
return (
<div className="App">
<button onClick={click}>click</button>
{
carsState.map(c => {
return <p key={c.name}>{c.name} - meta:
{c.meta.map((m, k) => <span key={k}>{m.title}</span>)}</p>
})
}
</div>
);
}
如果用户单击该按钮,它应该更改数组中的第一项。现在,如果我单击该按钮,新的项目将添加到列表的末尾,但它应该会更改第一个项目,因为id是相同的。
为什么代码不能工作,如何更改以获得预期的结果?
演示:https://codesandbox.io/s/ecstatic-sound-rkgbe?file=/src/App.tsx:56-64
发布于 2021-10-03 07:00:10
问题出在下面这一行:
setCarsState([...carsState, newItem])
您必须过滤掉那些id不等于newItem.id
的项,然后添加newItem
,如下所示:
setCarsState([...carsState.filter(e => e.id !==newItem.id),newItem]);
import "./styles.css";
import React from "react";
const carsData = [
{ name: "first car", id: 1, meta: [{ id: 1, title: "first meta" }] },
{ name: "second car", id: 2, meta: [{ id: 2, title: "second meta" }] },
{ name: "third car", id: 3, meta: [{ id: 4, title: "last meta" }] }
];
export default function App({ cars = carsData }) {
const [carsState, setCarsState] = React.useState(cars);
const newItem = {
name: "first car",
id: 1,
meta: [{ id: 10, title: "added meta" }]
};
const click = () => {
setCarsState([...carsState.filter(e => e.id !==newItem.id),newItem]);
};
return (
<div className="App">
<button onClick={click}>click</button>
{carsState.map((c) => {
return (
<p key={c.name}>
{c.name} - meta:
{c.meta.map((m, k) => (
<span key={k}>{m.title}</span>
))}
</p>
);
})}
</div>
);
}
这是sandbox
发布于 2021-10-03 07:12:08
好的,你的代码就像你说的那样-as push
to the array
。因为你并没有真正告诉它去做其他的事情。
如果您希望用新项替换旧项,如果它们具有相同的id值。我建议将初始array
更改为object
,其中每个value
的key
是项的id。
我强烈建议你这样做,如果你想通过他们的id与你的项目进行交互,一旦你将你的操作扩展到包含很多项目,一个数组很快就会变得低效。
import React from 'react';
//notice we changed carsData from an array into an object. Notice
//the keys are equal to each item's id
const carsData = {
1:{name: "first car", id: 1, meta: [{id:1, title:'first meta'}]},
2:{name: "second car", id: 2, meta: [{id:2, title:'second meta'}]},
3:{name: "third car", id: 3, meta: [{id:4, title:'last meta'}]},
}
export default function App({cars = carsData}) {
const [carsState, setCarsState] = React.useState(cars)
const newItem = {name: "first car", id: 1, meta: [{id:10, title:'added meta'}]}
const click = () => {
//We use the id of the new item as the key,
//this will enable us to replace the value of the old item because
//objects can't have the same key twice.
setCarsState({...carsState, [newItem.id]: newItem})
console.log(carsState)
}
return (
<div className="App">
<button onClick={click}>click</button>
{
//instead of mapping the array, now we map the
//values of our object by using the method
//Object.values(carsState) which returns an array
//of values from our object.
Object.values(carsState).map(c => {
return <p key={c.name}>{c.name} - meta:
{c.meta.map((m, k) => <span key={k}>{m.title}</span>)}</p>
})
}
</div>
);
}
使用此解决方案将允许您按其id获取每一项。只需输入
carsData[id_of_item]
如果您的carsData
是以来自DB的数组的形式出现的,那么您可以将其映射到一个对象中
var carsDataObject = {}
cars.map(item => carsDataObject[item.id] = item)
const [carsState, setCarsState] = React.useState(carsDataObject)
然后,您可以使用carsDataObject
而不是carsData
数组
https://stackoverflow.com/questions/69425965
复制相似问题