当我使用选择器正常功能时,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();
主要问题:我试图在选择器中使用一个函数来重构数据并加入另一个变量,在这种情况下我的组和他们的 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();