微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

当我使用选择器普通函数时,ReactJs 状态在循环中触发

如何解决当我使用选择器普通函数时,ReactJs 状态在循环中触发

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

我有这个选择器: 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 运行您的选择器并检查结果是否与之前收到的结果相同(参考比较)。如果结果不同,则存储新结果并强制重新渲染。如果结果相同,则不会替换旧结果,也不会触发重新渲染。

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

我认为处理这个问题的最好方法是让你的选择器尽可能简单,或者使用某种形式的更复杂的记忆,比如 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();

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。