我在react应用程序中使用redux store来存储我的费用等数据。
现在,我在其中一个组件中使用这些费用来计算TODO徽章计数,如下所示
const [badgeValue, setBadgeValue] = useState(0);
const expenses = useSelector(({ expenses }: RootState) => expenses.items);
useEffect(() => {
const setBadge = async () => {
const badgeNumber = await calculateRequestBadgeNumber(expenses);
setBadgeValue(badgeNumber);
};
setBadge();
return () => setBadgeValue(0);
}, [expenses]);这与预期的一样。然而现在,当我想像这样过滤掉删除的费用时,我遇到了一个奇怪的副作用:
const expenses = useSelector(({ expenses }: RootState) =>
expenses.items.filter((expense: Expense) => !expense.deleted)
);这会导致调用useEffects的无限循环。为什么会发生这种情况?
发布于 2020-09-20 05:20:02
与大多数涉及React钩子的事情一样,所涉及的对象的身份(例如,您使用===测试的内容)在这里很重要。当expenses的标识与上次渲染不同时,将触发您的效果。
选择器A
此挂钩返回Redux状态的expenses属性的items属性。如果状态没有改变,items属性的标识也不会改变。
const expenses = useSelector(({ expenses }: RootState) => expenses.items);选择器B
这将返回在items数组上调用filter的结果。filter方法返回一个全新的数组。
const expenses = useSelector(({ expenses }: RootState) =>
expenses.items.filter((expense: Expense) => !expense.deleted)
);您所观察到的是Selector B在组件每次呈现时都返回一个新值,因此该效果被频繁触发。
Now -如果状态没有改变,但仅当传递给它的选择器函数的标识保持不变时,使用useSelector cache its return value进行重用。您可以通过在模块作用域而不是组件中命名选择器来确保这一点。
const filteredExpenses = ({ expenses }: RootState) =>
expenses.items.filter((expense: Expense) => !expense.deleted);
const MyComponent = () => {
const [badgeValue, setBadgeValue] = useState(0);
const expenses = useSelector(filteredExpenses);
useEffect(() => {
const setBadge = async () => {
const badgeNumber = await calculateRequestBadgeNumber(expenses);
setBadgeValue(badgeNumber);
};
setBadge();
return () => setBadgeValue(0);
}, [expenses]);
return <StuffToRender />;
};https://stackoverflow.com/questions/63972966
复制相似问题