当我使用选择器正常功能时,ReactJs 状态在循环中触发

ReactJs a state is triggeing in a loop when I use a selector normal function

主要问题:我试图在选择器中使用一个函数来重构数据并加入另一个变量,在这种情况下我的组和他们的 children 作为项目放在一起,问题是函数尽管状态没有改变,但每次都会在无限循环中被调用。

我有这个选择器: const groups = useSelector(state => selectProductGroups(state));

函数是这个:

  const groups = state.PlatformsReducer.groups;
  const items = state.PlatformsReducer.items;
  return groups.reduce((ac, g) => {
    g.items = items.filter(i => i.groupId == g.productNumber);
    if (ac[g.platformId]) {
      ac[g.platformId].push(g);
    } else {
      ac[g.platformId] = [g];
    }
    return ac;
  }, {});
};

So when I use a useEffect to detect if the groups variable has changed the useEffect is triggered in a loop despite the variable groups still empty.

Do you know why? or How to prevent this.

I now the problem is the function in the selector, but I don't know how to prevent this case.

这与 useSelector 挂钩的作用有关 internally

useSelector 运行您的选择器并检查结果是否与先前收到的结果相同(参考比较)。如果结果不同,则存储新结果并强制重新渲染。如果结果相同,则不会替换旧结果,也不会触发重新渲染。

这意味着每次存储更新时,即使它是状态的不相关部分,您的复杂函数也会 运行 确定结果是否已更改。在你的情况下,它总是一个新的参考,因此总是一个变化。

我认为处理此问题的最佳方法是让您的选择器尽可能简单,或者使用某种形式的更复杂的记忆,如 reselect 提供的。

下面是一个示例,说明您如何能够使选择器保持简单,但仍然可以轻松地使用自定义挂钩重用您的产品组选择。

const useProductGroups = () => {
    // Get groups from the store. 
    // As the selector does not create a new object it should only 
    // trigger a rerender when groups changes in the store.
    const groups = useSelector(state => state.PlatformsReducer.groups);

    // Get items from the store, 
    // As the selector does not create a new object it should only 
    // trigger a rerender when items changes in the store.
    const items = useSelector(state => state.PlatformsReducer.items);

    // Reduce the group collection as desired inside of a useMemo 
    // so that the reduction only occurs when either items or groups 
    // changes.
    const productGroups = useMemo(() => {
        return groups.reduce((ac, g) => {
            g.items = items.filter(i => i.groupId == g.productNumber);

            if (ac[g.platformId]) {
                ac[g.platformId].push(g);
            } else {
                ac[g.platformId] = [g];
            }

            return ac;
        }, {});
    }, [groups, items] /* dependency array on items / groups */);

    // return the calculated product groups
    return productGroups;
}

然后您可以在函数组件中使用自定义挂钩:

const groups = useProductGroups();