仅在附加父节点后有条件地渲染延迟加载组件会导致无限循环

问题描述 投票:0回答:1

反应版本:18.3.1

重现步骤

创建一个在 a 内渲染子级的组件,但仅在它获得对该 div 的引用之后(通过将 div 节点置于某种状态) 将延迟加载的组件作为子组件传递

所以基本上是这样的:

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>
);

代码示例链接:

https://stackblitz.com/edit/vitejs-vite-uqnpwm?file=src%2FApp.jsx

当前行为

由于无限循环而导致运行时错误。

预期行为

延迟加载的组件已渲染。

reactjs lazy-loading infinite-loop react-suspense react-18
1个回答
0
投票

您可以使用

const ref = useRef()
捕获节点的引用,但我不理解您的用例,Suspense 内部的内容被视为一个单元,因此即使一个组件需要时间,所有其他组件都会渲染一次需要时间解决的问题,总之不需要添加 RenderAfterMount 就可以正常工作了


import { Suspense, lazy, useRef, useState } from 'react';
import './styles.css';

const LazyLoadedComponent = lazy(
  () =>
    new Promise((resolve) => {
      setTimeout(
        () =>
          resolve({
            default: () => (
              <div style={{ background: 'green' }}>Lazy loaded component</div>
            ),
          }),
        5000
      );
    })
);

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <Suspense>
        <SomeRandomComponent/>
          <LazyLoadedComponent />
      </Suspense>
    </div>
  );
}

const SomeRandomComponent = (props) => {
  return <div>rendering</div>
};


在此示例中,文本渲染和实际延迟加载的组件都将在 5 秒后渲染

© www.soinside.com 2019 - 2024. All rights reserved.