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

父节点挂载后条件渲染懒加载组件引发无限循环问题

React 18.3.1 懒加载组件引发无限循环问题

复现步骤

  • 创建组件,仅在获取到div节点引用后,才在该div内渲染子组件(原代码将div节点存入state)
  • 传入懒加载组件作为子元素

示例代码

import { Suspense, lazy, useState } from 'react';

const LazyLoadedComponent = lazy(
  () =>
    new Promise((resolve) => {
      setTimeout(
        () =>
          resolve({
            default: () => <div>Lazy loaded component</div>,
          }),
        500,
      );
    }),
);

const RenderAfterMount = (props) => {
  const [node, setNode] = useState(null);

  return <div ref={setNode}>{node && props.children}</div>;
};

export const App = () => (
  <Suspense>
    <RenderAfterMount>
      <LazyLoadedComponent />
    </RenderAfterMount>
  </Suspense>
);

当前行为

运行时出现无限循环错误

预期行为

成功渲染懒加载组件

问题分析与解决方案

问题根源在于将DOM节点存入state:当node从null变为DOM节点时,会触发组件重渲染并开始渲染懒加载组件。此时Suspense会捕获组件的加载状态,触发React暂停渲染并重新尝试,这个过程中div的ref回调会再次执行,调用setNode更新state,进而再次触发重渲染,形成无限循环。

解决方法是改用useRef存储DOM节点,因为ref的更新不会触发组件重渲染:

import { Suspense, lazy, useRef, useEffect, useState } from 'react';

const LazyLoadedComponent = lazy(
  () =>
    new Promise((resolve) => {
      setTimeout(
        () =>
          resolve({
            default: () => <div>Lazy loaded component</div>,
          }),
        500,
      );
    }),
);

const RenderAfterMount = (props) => {
  const nodeRef = useRef(null);
  const [isMounted, setIsMounted] = useState(false);

  useEffect(() => {
    if (nodeRef.current) {
      setIsMounted(true);
    }
  }, []);

  return <div ref={nodeRef}>{isMounted && props.children}</div>;
};

export const App = () => (
  <Suspense fallback={<div>Loading...</div>}>
    <RenderAfterMount>
      <LazyLoadedComponent />
    </RenderAfterMount>
  </Suspense>
);

通过useRef存储DOM节点,配合useEffect在组件挂载后仅触发一次状态更新,就能避免state反复更新导致的无限循环,同时正常渲染懒加载组件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:28:23