You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,后续加载必然出问题。

正确的优化方案

  1. 父组件的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])
  1. 优化组件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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 06:00:02