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

React函数组件用默认参数搭配useEffect出现无限循环该如何解决?

React函数组件对象类型默认参数触发useEffect无限重渲染的规避方案

以下是除defaultProps外的几个常用最优方案,可根据场景选择:

方案1:将默认对象提取到组件外部定义

组件外部的常量仅会初始化一次,全生命周期内引用稳定,不会出现每次渲染生成新实例的问题,适合默认值不需要依赖组件内部状态/属性的场景。

// 组件外定义稳定的默认对象
const DEFAULT_QUERY = { page: 1, pageSize: 10 };

function ListComponent(query = DEFAULT_QUERY) {
  useEffect(() => {
    // 副作用逻辑
    getList(query);
  }, [query]);

  return <div>列表组件</div>
}

方案2:解构参数后仅将原始类型值放入依赖数组

如果副作用逻辑仅用到参数的部分属性,可直接解构出对应原始类型的属性,给原始类型设置默认值,依赖数组仅传入这些原始值即可,完全避免对象引用变化的影响,是性能最优的方案。

function ListComponent(query = {}) {
  // 解构出需要的属性,给原始类型设默认值
  const { page = 1, pageSize = 10 } = query;

  useEffect(() => {
    getList({ page, pageSize });
    // 仅依赖原始类型值,不会触发无效重渲染
  }, [page, pageSize]);

  return <div>列表组件</div>
}

方案3:用useMemo缓存最终参数对象

如果默认值需要依赖组件内部状态、props做动态计算,可用useMemo缓存处理后的参数对象,依赖数组仅传入计算过程用到的原始类型值即可。

function ListComponent(initQuery) {
  const [userCustomSize, setUserCustomSize] = useState(10);

  // 缓存参数对象,仅当依赖的原始值变化时才生成新对象
  const finalQuery = useMemo(() => {
    return {
      page: 1,
      pageSize: userCustomSize,
      ...initQuery
    };
  }, [initQuery?.page, initQuery?.pageSize, userCustomSize]);

  useEffect(() => {
    getList(finalQuery);
  }, [finalQuery]);

  return <div>列表组件</div>
}

方案4:深比较判断对象实际变化

如果必须将完整对象作为依赖、且对象结构复杂属性多,可在useEffect内通过深比较判断对象内容是否真的发生变化,仅内容变化时才执行副作用逻辑,适合对性能影响不大的复杂对象场景。

import isEqual from 'lodash/isEqual';

function ListComponent(query = { page: 1, pageSize: 10 }) {
  const prevQueryRef = useRef();

  useEffect(() => {
    // 仅对象内容实际变化时才执行副作用
    if (!isEqual(query, prevQueryRef.current)) {
      prevQueryRef.current = query;
      getList(query);
    }
    // 确认逻辑无误可加以下注释忽略eslint依赖警告
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [query]);

  return <div>列表组件</div>
}

内容的提问来源于stack exchange,提问作者Auskennfuchs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 09:24:05