父组件传入数组作为useMemo依赖触发无限重渲染问题
问题原因
每次父组件渲染时,keys={['title', 'description']}会创建一个新的数组引用——JavaScript里数组字面量每次执行都会生成全新的对象,哪怕内容完全一致。这就导致子组件useMemo的依赖项keys每次都不相等,useMemo会重新执行创建Fuse实例。如果Fuse实例的变化又触发了父组件的状态更新(比如子组件的筛选回调修改了父组件状态),就会形成「父组件渲染→传新keys→子组件useMemo重新计算→触发父组件状态更新→父组件再渲染」的无限循环。
解决办法
针对这种静态数组的场景,有三种直接有效的处理方式:
1. 父组件用useMemo缓存keys数组
在父组件里把静态数组用useMemo包裹,保证每次渲染时引用稳定:
const Parent = () => { const keys = React.useMemo(() => ['title', 'description'], []); return <FilterInput data={data} keys={keys} />; };
2. 把keys定义为组件外部的常量
如果keys是固定不变的静态值,直接放到组件外部,彻底避免每次渲染重新创建数组:
// 组件外部定义,全局唯一引用 const SEARCH_KEYS = ['title', 'description']; const Parent = () => { return <FilterInput data={data} keys={SEARCH_KEYS} />; };
3. 子组件内部做浅比较优化(备选方案)
如果无法修改父组件的传参逻辑,可以在子组件里手动对keys做浅比较,结合useMemo和useRef判断是否需要更新Fuse实例:
const FilterInput = ({ data, keys }) => { const prevKeysRef = React.useRef(); const stableKeys = React.useMemo(() => { // 浅比较数组内容是否一致 if (prevKeysRef.current?.length !== keys.length) { prevKeysRef.current = keys; return keys; } for (let i = 0; i < keys.length; i++) { if (prevKeysRef.current[i] !== keys[i]) { prevKeysRef.current = keys; return keys; } } return prevKeysRef.current; }, [keys]); const fuse = React.useMemo(() => { return new Fuse(data, { keys: stableKeys }); }, [data, stableKeys]); // 其他组件逻辑... };
内容的提问来源于stack exchange,提问作者Trufa
相关产品推荐
相关产品推荐

