我有一个将商品添加到购物车的功能。我试图在单击按钮时为新对象项生成唯一键。我有new Date().getTime()
根据点击频率进行此操作。我在函数内部测试了console.log,它为每个新对象生成不同的unique_id
号。当我尝试将对象的现有状态数组与新的item
对象结合在一起时,问题就开始了。现有的所有unique_id
都将覆盖为最新的unique_id
。我也在状态数组中使用React useState钩子。 React有点相关,因为状态数组不应直接编辑,而应通过setter方法进行编辑。
我尝试了.push
,.concat
,Array.from
,扩展运算符,在函数内部和外部循环和分配变量的组合。我知道这是pass-by-reference
与pass-by-value
的局面,因为这些数组方法只是浅表副本。
const [cart, setCart] = useState([])
const addItem = (item) => {
let cartArr = cart
item['unique_id'] = new Date().getTime()
setCart([...cartArr, item])
}
预期:
[
{id: 1, price: 10.11, title: "The Art Of War", unique_id: 1565675696123},
{id: 1, price: 10.11, title: "The Art Of War", unique_id: 1565675696256},
{id: 1, price: 10.11, title: "The Art Of War", unique_id: 1565675696377}
]
但得到:
[
{id: 1, price: 10.11, title: "The Art Of War", unique_id: 1565675696377},
{id: 1, price: 10.11, title: "The Art Of War", unique_id: 1565675696377},
{id: 1, price: 10.11, title: "The Art Of War", unique_id: 1565675696377}
]
答案 0 :(得分:1)
代替在数组中推送值,您可以连接数组和对象,请参见下面的代码供您参考
const [cart, setCart] = useState([]);
const addItem = item => {
item["unique_id"] = new Date().getTime();
setCart([...cart, item]);
};
这是codeandbox的link
答案 1 :(得分:0)
正如我在评论中提到的,这取决于您呼叫addItem
的频率。
下面的代码片段显示了如果您连续调用addItem
,所有项目都会(几乎总是)获得相同的时间:
let cart = [];
const addItem = (item) => {
let cartArr = cart;
let currentTime = new Date().getTime();
item['unique_id'] = currentTime;
cartArr.push(item);
cart = cartArr;
}
addItem({ price: 10 });
addItem({ price: 11 });
addItem({ price: 12 });
console.log(cart);
但是,在通过引入console.log
添加一些延迟之后,时间戳是不同的(不保证):
let cart = [];
const addItem = (item) => {
let cartArr = cart;
let currentTime = new Date().getTime();
console.log('Price: ' + item.price);
console.log('Current time: ' + currentTime);
item['unique_id'] = currentTime;
cartArr.push(item);
cart = cartArr;
}
addItem({ price: 10 });
addItem({ price: 11 });
addItem({ price: 12 });
console.log(cart);
所以,在这里,我认为React状态与时间戳或数组操作无关。
答案 2 :(得分:0)
正如@fiveelements所说,由于Date.now()
并不是生成随机值的可靠方法,因此会产生id冲突。幸运的是,浏览器具有恰好可以生成随机值的新功能。您可以尝试将其用作ID:
const id = window.crypto.getRandomValues(new Uint32Array(10))[0];
console.log(id);
您可以阅读有关window.crypto object on MDN的更多信息。所有现代浏览器都支持该功能,包括IE11:https://caniuse.com/#search=crypto。
如果您是从数据库之类的地方获取数据的,则可能已经有了某种可以使用的唯一ID。如果您可以使key
在渲染之间保持一致,则可以避免不必要的重新渲染,从而提高性能。但是,如果您没有任何ID,此代码段可以帮助您即时生成它们。
您也可以选中此CodePen。
答案 3 :(得分:0)
该问题与React无关。执行的循环恰好在同一时间戳下完成。
我建议不要模拟通过循环在购物车中添加多个物品。
var arr = [];
for(let i = 0; i < 10; i++){
arr.push(new Date().getTime())
}
console.log(arr);
答案 4 :(得分:0)
到目前为止,您可能一直都想不出来,时间戳很烂,无法做出反应作为键。
重要-React希望使用 STABLE 键,键分配应该完成一次,并且每个项目每次都应获得相同的键,以便React可以发挥其创造价值的魔力更改并决定何时重新渲染。
但是new Date
函数永远不会为您提供STABLE密钥,始终不一致。函数的每个新值都会赋予唯一键。
唯一的应该是有问题的组件,而不是全局的应用程序,以避免重新渲染该组件。
始终最好使用数据库中的id
之类的标识符。
如果不可用
我建议使用shortid
来生成密钥。
步骤:-
1)npm install shortid --save
2)import shortid from 'shortid';
3)用法
<li key={shortid.generate()}>
{value}
</li>
希望有帮助!
答案 5 :(得分:0)
cartArr
变量。
const [cart, setCart] = useState([])
const addItem = (item) => {
item['unique_id'] = new Date().getTime()
let newItem = Object.assign({}, item)
setCart([...cart, newItem])
}