Javascript 反应-筛选存储中的对象会导致递归/无限循环

Javascript 反应-筛选存储中的对象会导致递归/无限循环,javascript,reactjs,use-effect,Javascript,Reactjs,Use Effect,我在react应用程序中使用redux store来存储我的开支等数据 现在我在其中一个组件中使用这些费用来计算TODO徽章计数,如下所示 const [badgeValue, setBadgeValue] = useState(0); const expenses = useSelector(({ expenses }: RootState) => expenses.items); useEffect(() => { const setBadge = async () =

我在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钩子的事情一样,所涉及对象的标识(例如,您使用
==
测试的内容)在这里很重要。当
费用
的标识与上次渲染不同时,将触发效果


选择器A 这个钩子返回Redux状态的
expenses
属性的
items
属性。如果状态不变,则
属性的标识也不会改变

const expenses=useSelector(({expenses}:RootState)=>expenses.items);

选择器B 这将返回调用items数组上的
filter
的结果。filter方法返回一个全新的数组

const expenses=useSelector({expenses}:RootState)=>
费用.项目.过滤器((费用:费用)=>!费用.已删除)
);

您观察到的是选择器B在每次组件渲染时都返回一个新值,因此效果被触发的频率太高

现在-如果状态未更改,但仅当传递给它的选择器函数的标识保持不变时,才重新使用。您可以通过在模块作用域中命名选择器而不是组件来确保这一点

const filteredExpenses=({expenses}:RootState)=>
费用.项目.过滤器((费用:费用)=>!费用.已删除);
常量MyComponent=()=>{
const[badgeValue,setBadgeValue]=useState(0);
施工费用=使用选择器(过滤器费用);
useffect(()=>{
const setBadge=async()=>{
const badgeNumber=等待计算请求badgeNumber(费用);
setBadgeValue(徽章编号);
};
setBadge();
return()=>setBadgeValue(0);
},[费用];
返回;
};