在使用Nextjs中的Suspense和动态导入时,出现了一个错误:“该Suspense边界在完成水合之前接收到了更新”。

28

我正在尝试使用Suspense和Nextjs中的动态导入来惰性加载一组数据。但是遇到以下错误:

Error: This Suspense boundary received an update before it finished hydrating. This caused the boundary to switch to client rendering. The usual way to fix this is to wrap the original update in startTransition.

我尝试使用startTransition(),但是不知道如何使用它。

DataList.tsx:

import React, { useState } from "react";

interface Props {
  data: any[];
}

const DataList = ({ data }: Props) => {
  return (
    <div>
      {data &&
        data.map((item) => {
          return (
            <div key={item._id}> 
              {item.title} 
            </div>
          );
        })}
    </div>
  );
};
export default DataList;

DataPage.tsx

import React, { Suspense, useEffect, useState } from "react";
import dynamic from "next/dynamic";
const DataList = dynamic(() => import("./DataList"), {
  suspense: true,
});

interface Props {}

const Projects = ({}: Props) => {

  const [data,setData] = useState<any[]>();

  useEffect( () => { 
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(json => setData(json))
  } , []) 

  return (
    <>
      <Suspense fallback={<p>LOADING</p>}>
        <DataList data={data} />
      </Suspense>
    </>
  );
};


export default DataPage;

@beig 我已经修复了。你可以再次检查代码。 - Hashem Mashem
1
这段代码片段不足以重现问题(我已经尝试过了,它并没有引起你所报告的错误)。 - Maël Nison
2
你解决了吗?我也遇到了同样的问题。 - Mel
1
这可能是React中的一个bug,您可以在此处查看该问题:https://github.com/facebook/react/issues/25625,并且PR:https://github.com/facebook/react/pull/25692。 - Jalal
@Jalal 这个问题似乎仍然是开放状态,尽管PR已经合并。你有什么想法,这可能会何时生效? - Aakash Thakur
显示剩余3条评论
4个回答

1

首先,您正在使用动态导入

在Next.js中,动态函数用于仅在需要时动态加载组件,而不是将其包含在应用程序的初始捆绑包中。

在您的情况下,似乎DataList组件是呈现项目初始视图所必需的主要组件。

因此,在我的情况下,删除动态导入解决了我的问题,我不再收到Suspense错误。

因此,将导入更改为以下内容应解决您的问题:

import DataList from './DataList';

以下是一些使用动态加载的示例:

1- 大型第三方库:如果您在应用程序中使用大型第三方库,它可能会显著增加初始捆绑包大小。您可以使用动态加载仅加载特定页面或用户交互所需的库部分。

2- 条件组件:如果您有仅在某些用户交互或页面中需要的组件,则可以使用动态加载它们,而不是将它们包含在初始捆绑包中。

3- 加载缓慢的组件:如果您有需要很长时间才能加载或呈现的组件,则可以使用动态加载它们,而不是减慢初始页面加载速度。

4- 服务器端渲染兼容性问题:如果您有不兼容服务器端渲染的组件,则可以使用带有ssr: false选项的动态加载将其排除在服务器端渲染过程之外。

5- 需要注意的是,使用动态加载可能会给您的应用程序增加额外的复杂性,因此最好谨慎使用,并且只有在提供显著性能优势时才使用它。此外,重要的是要彻底测试您的应用程序,以确保动态加载的组件按预期工作,特别是在服务器端渲染方面。


删除动态内容对我有用,谢谢! - wassim AJ

0

你能详细说明一下吗?为什么添加 ssr:false 就可以解决过渡问题? - Jalal
@Jalal ssr : false 是一个标志,它告诉你在构建时(服务器端导入)不会导入组件,而仅用于客户端。 - Mallikarjun M G

0
使用startTransition而不是useEffect! 我这样做了,我的问题解决了...

这并没有回答问题。一旦你拥有足够的声望,你就可以评论任何帖子;相反,提供不需要提问者澄清的答案。- 来自审查 - Hamza Rashid

0
有时在使用React的Concurrent Mode功能时,可能会出现错误。如果您在应用程序中使用Concurrent Mode,它可能会引入不同的渲染行为。请确保您正确使用它。
以下是使用startTransition修改过的代码版本,以帮助防止错误的出现:
import React, { Suspense, useEffect, useState } from "react";
import dynamic from "next/dynamic";
const DataList = dynamic(() => import("./DataList"), {
  suspense: true,
});

interface Props {}

const Projects = ({}: Props) => {
  const [data, setData] = useState<any[]>();

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(json => {
        startTransition(() => {
          setData(json);
        });
      });
  }, []);

  return (
    <>
      <Suspense fallback={<p>LOADING</p>}>
        <DataList data={data} />
      </Suspense>
    </>
  );
};

export default Projects;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接