React Native如何正确做组件memoization?areEqual是否需要比对方法类props?
结论先行:你必须在比对逻辑中加入函数类props的比对,当前你的实现已经存在隐性闭包问题,只是暂时没触发而已。
你当前代码的隐藏问题
你现在没有比对onEndReached,会导致组件B永远持有的是第一次渲染时传入的fetchMoreData函数:
- 父组件A每次重渲染都会生成新的
fetchMoreData实例,新的函数会闭包捕获当前最新的data状态 - 但只要
data和isLoading没有变化,B就不会重渲染,也就拿不到最新的fetchMoreData,当旧的fetchMoreData执行时,内部用到的data是过时的初始值,会导致你setData([...data, ...newData])时丢失之前已经加载的历史数据。
你现在运行正常只是测试场景刚好没触发bug:比如你每次触发加载后data都会更新,顺带触发了B的重渲染,刚好把新的fetchMoreData传进去了。一旦父组件因为其他无关状态更新触发重渲染,生成的新回调就没法同步到B,后续加载必然出问题。
正确的优化方案
- 父组件的
fetchMoreData用useCallback包裹,保证函数引用的稳定性,同时修改setData为函数式更新,避免闭包陷阱:
const fetchMoreData = useCallback(async () => { if(isFetching.current) return; isFetching.current = true; setIsLoading(true); try { const newData = await /* 你的接口请求逻辑 */ // 函数式更新不需要依赖外部的data变量,减少useCallback依赖 setData(prevData => [...prevData, ...newData]); } catch(err) { // 错误处理逻辑 } setIsLoading(false); isFetching.current = false; // useState返回的setData、setIsLoading本身是稳定引用,不会变化 }, [setData, setIsLoading])
- 优化组件B的
memo比对逻辑,一是去掉性能极差且极易出错的JSON.stringify比对(数据量大时序列化耗时极高,遇到undefined、函数、循环引用会直接出错),二是加入onEndReached的比对:
const B = memo(({ data, isLoading, onEndReached }) => { return ( <FlatList data={data} isLoading={isLoading} onEndReached={onEndReached} /> ); }, (prevProps, nextProps) => { return prevProps.data === nextProps.data && prevProps.isLoading === nextProps.isLoading && prevProps.onEndReached === nextProps.onEndReached; });
因为你每次更新data都是返回全新的数组([...data, ...newData]),直接比对数组引用就足够判断数据是否变化,完全不需要序列化。
内容的提问来源于stack exchange,提问作者Raul
相关产品推荐
相关产品推荐

