在反应状态下附加多维数组

时间:2021-01-13 16:58:41

标签: javascript arrays reactjs

我正在尝试附加处于反应状态的数组:

  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, [{},{},{},..{}]].

我希望有人知道发生了什么?已经修复了一段时间了。

1 个答案:

答案 0 :(得分:1)

问题在于您的履行处理程序关闭了 productsstale 副本(作为初始状态的一部分的空数组)。在 useEffect(或 useCallbackuseMemo 等)钩子中,您不能使用任何不属于您提供给钩子的依赖项数组的状态项。在您的情况下,您只想获取挂载数据,因此空依赖数组是正确的。这意味着您不能在回调中使用任何状态项。

你可以做的是使用状态设置器的回调形式:

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 10 的请求之前完成,您的数组在第一次状态更新后将如下所示:

[undefined, undefined, {/*data for id = 2*/}]

您需要确保在呈现组件时处理这些 undefined 条目。