我正在尝试附加处于反应状态的数组:
const [ products, setProducts ] = useState([])
useEffect(() => {
config.categories.forEach(category => {
service.getCategory(category.name).then(data => {
const copy = JSON.parse(JSON.stringify(products))
copy[category.id] = data
setProducts(copy)
})
})
},[])
service.getCategory() 通过 HTTP 返回数组获取数据。 products 是嵌套数组,或者至少它假设是。 config.category 定义为:
categories: [
{
name: 'product1',
id: 0
},
{
name: 'product2',
id: 1
},
{
name: 'product3',
id: 2
}]
}
最终产品应该被附加 3 次,并且它应该包含 3 个包含这些类别产品的数组。取而代之的是 products 数组最终只包含来自最后一次 HTTP fetch 的数据,这意味着最终的数组看起来像这样
products = [null, null, [{},{},{},..{}]].
我希望有人知道发生了什么?已经修复了一段时间了。
答案 0 :(得分:1)
问题在于您的履行处理程序关闭了 products
的 stale 副本(作为初始状态的一部分的空数组)。在 useEffect
(或 useCallback
或 useMemo
等)钩子中,您不能使用任何不属于您提供给钩子的依赖项数组的状态项。在您的情况下,您只想获取挂载数据,因此空依赖数组是正确的。这意味着您不能在回调中使用任何状态项。
你可以做的是使用状态设置器的回调形式:
const [ products, setProducts ] = useState([]);
useEffect(() => {
config.categories.forEach(category => {
service.getCategory(category.name).then(data => {
setProducts(products => { // Use the callback form
const copy = products.slice(); // Shallow copy of array
copy[category.id] = data; // Set this data
return copy; // Return the shallow copy
});
});
});
}, []);
或者更简洁(但更难调试!)没有解释性注释:
const [ products, setProducts ] = useState([]);
useEffect(() => {
config.categories.forEach(category => {
service.getCategory(category.name).then(data => {
setProducts(products => Object.assign([], products, {[category.id]: data}));
});
});
}, []);
它们都使用与原始代码相同的逻辑,但正确更新数组。 (他们也只制作数组的浅拷贝。不需要深拷贝,我们不修改任何对象,只修改数组本身。)
但是,每次 getCategory
完成时都会更新状态 - 因此,在您的三个类别的示例中更新了三次。如果 id
2
的请求在 id
1
或 0
的请求之前完成,您的数组在第一次状态更新后将如下所示:
[undefined, undefined, {/*data for id = 2*/}]
您需要确保在呈现组件时处理这些 undefined
条目。