javascript - React - 过滤存储中的对象会导致递归/无限循环
问题描述
我在我的 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 的无限循环。为什么会这样?
解决方案
与大多数涉及 React 钩子的事情一样,所涉及的对象的身份(例如,您使用 测试的内容===
)在这里很重要。当 的标识expenses
与上次渲染不同时,将触发您的效果。
选择器 A
这个钩子返回你的 Redux 状态items
的expenses
属性。如果状态不改变,items
财产的身份也不会改变。
const expenses = useSelector(({ expenses }: RootState) => expenses.items);
选择器 B
这将返回调用filter
items 数组的结果。filter 方法返回一个全新的数组。
const expenses = useSelector(({ expenses }: RootState) =>
expenses.items.filter((expense: Expense) => !expense.deleted)
);
您正在观察的是 Selector B 每次组件呈现时都会返回一个新值,因此效果被触发得太频繁了。
现在 -如果状态没有改变,但只有当你传递给它的选择器函数的标识保持不变时,useSelector
可以缓存它的返回值以重用。您可以通过在模块范围内命名选择器而不是组件来确保这一点。
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 />;
};
推荐阅读
- angular - mat-checkbox 意外行为
- bash - 为每个文件创建一个文件夹
- python - 如何结合散点图中的两个matplotlib(python)颜色图
- perl - Perl 脚本为 awk 命令引发语法错误
- java - 在应用订单之前操作存储在 Firebase 文档字段中的值
- android - Oculus Quest 的麦克风权限
- scala - 如何使用 spark/scala 从一个数据帧中获取不在另一个数据帧中的行
- java - 使用 Google Cloud Messaging 时无法解析方法 addOnCompleteListener
- django - 根据 Django Rest Framework 中的用户组路由到不同的数据库
- php - 无法在cakephp中显示上标