当依赖对象属性未知时,如何触发useEffect重新执行?
如何在未知对象属性时让useEffect随对象值变化重新执行?
我希望当对象的值发生变化时重新执行useEffect。之前我了解到可以用useMemo解决对象引用问题,已知属性的场景示例代码如下:
// 当name或age变化时重新执行useEffect const [age, setAge] = useState(0); const [name, setName] = useState(''); const [darkMode, setDarkMode] = useState(false); /* 需要用useMemo的原因: 如果直接写person = {age: age, name: name},哪怕darkMode变化,这个对象的引用也会更新,导致useEffect不必要触发, 所以用useMemo缓存对象,只在age和name变化时更新引用 */ const person = useMemo(() => { return { age: age, name: name }; }, [age, name]); useEffect(() => { console.log('useEffect run'); }, [person]); // 或者直接依赖对象属性 /* useEffect(() => { console.log('useEffect run'); }, [person.age, person.name]); */
但如果我不知道person对象的具体属性,该怎么让useEffect依赖对象的属性变化重新执行?我自己想到了两种方案,但不确定是不是最优解:
方案1:结合useMemo处理
// suggestion1 (using useMemo like that) const personValues = Object.keys(person).map((att) => person[att]); const personMemo = useMemo(() => { return { ...person}; }, [...personValues ]); useEffect(() => { console.log('useEffect run'); }, [personMemo]);
方案2:直接依赖对象属性值
// suggestion2 (don't use useMemo) const personValues = Object.keys(person).map((att) => person[att]); useEffect(() => { console.log('useEffect run'); }, [...personValues]);
我尝试把对象属性展开到useEffect的依赖数组里,觉得这种方法可行,想请教有没有更优的方案。
方案评价与更优解
对两种方案的评价
- 方案1存在冗余:
useMemo返回对象拷贝,依赖数组是对象的所有属性值,其实直接用属性值数组作为useEffect依赖即可,没必要额外做一次useMemo缓存。 - 方案2是可行的,但可以简化代码,不需要单独定义
personValues变量。
- 方案1存在冗余:
更简洁的浅层次对象实现
如果对象是浅层次结构(无嵌套对象/数组),可以直接把Object.values(person)放到useEffect的依赖数组中,省去中间变量:useEffect(() => { console.log('useEffect run'); }, [Object.values(person)]);Object.values(person)会返回对象所有属性值组成的数组,只要任意属性值变化,这个数组内容就会改变,触发useEffect重新执行。嵌套对象的处理方式
如果person包含嵌套对象/数组,浅层次的Object.values无法检测到内部值的变化(嵌套对象引用未改变时),可以选择:- 将对象序列化为JSON字符串(注意:该方法对函数、Symbol等特殊类型不友好):
useEffect(() => { console.log('useEffect run'); }, [JSON.stringify(person)]); - 使用第三方库提供的
useDeepCompareEffect(比如react-use库中的对应钩子),它基于深比较判断依赖是否变化,避免不必要的触发。
- 将对象序列化为JSON字符串(注意:该方法对函数、Symbol等特殊类型不友好):
内容的提问来源于stack exchange,提问作者Mustafa Saad
相关产品推荐
相关产品推荐

