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

React 18.3.0使用use钩子结合Suspense出现多次重渲染问题求助

问题描述

使用React 18.3.0-canary-3ff846d10-20230724 + Next.js 13.4.12,尝试通过React的use钩子结合Suspense实现数据请求时,遇到组件多次重渲染问题:控制台反复输出“render SuspenseTest”(约5至8次),直到加载完成显示“Done”。预期组件仅渲染一次,已尝试React.memo、useMemo、useCallback优化但无效,希望不依赖外部库解决该问题。

相关代码:

// src/pages/index.tsx
import { Suspense } from "react"
import Head from "next/head"
import SuspenseTest from "@/components/modules/SuspenseTest"

const Top = (): JSX.Element => {
  return (
    <>
      <Head>
        <title>Suspense Test</title>
      </Head>
      <main>
        <Suspense fallback={<div>Now Loading...</div>}>
          <SuspenseTest />
        </Suspense>
      </main>
    </>
  )
}

export default Top
// src/components/modules/SuspenseTest/index.tsx
import { use } from "react"

const fetcher = (): Promise<string> => {
  return new Promise((resolve) =>
    setTimeout(() => {
      resolve("Done")
    }, 5000),
  )

  // 实际业务中的请求逻辑
  // return axiosClient
  //   .get("/articles")
  //   .then((response) => {
  //     return response.data as Promise<Article[]>
  //   })
  //   .catch((error) => console.error(error))
}

const SuspenseTest = (): JSX.Element => {
  console.log("render SuspenseTest")

  const message = use<string>(fetcher())

  return <div>{message}</div>
}

export default SuspenseTest
解决方案

核心问题是每次组件渲染时都会创建新的Promise实例,触发Suspense反复挂起、恢复,导致多次重渲染。解决关键是稳定Promise实例,确保组件每次渲染使用同一个Promise。

方法1:用useMemo缓存Promise

通过useMemo包裹Promise创建逻辑,依赖项设为空数组,确保仅在组件首次渲染时创建一次Promise:

// src/components/modules/SuspenseTest/index.tsx
import { use, useMemo } from "react"

const fetcher = (): Promise<string> => {
  return new Promise((resolve) =>
    setTimeout(() => {
      resolve("Done")
    }, 5000),
  )
}

const SuspenseTest = (): JSX.Element => {
  console.log("render SuspenseTest")

  // 缓存Promise实例,避免每次渲染重复创建
  const dataPromise = useMemo(() => fetcher(), [])
  const message = use<string>(dataPromise)

  return <div>{message}</div>
}

export default SuspenseTest

方法2:将Promise提升到组件外部(静态创建)

如果请求不需要依赖组件的props或state,直接在组件外部定义Promise,整个应用生命周期内仅创建一次:

// src/components/modules/SuspenseTest/index.tsx
import { use } from "react"

// 组件外部静态创建Promise,仅执行一次
const dataPromise = new Promise<string>((resolve) =>
  setTimeout(() => {
    resolve("Done")
  }, 5000),
)

const SuspenseTest = (): JSX.Element => {
  console.log("render SuspenseTest")

  const message = use<string>(dataPromise)

  return <div>{message}</div>
}

export default SuspenseTest

为什么之前的优化无效?

React.memo、useMemo、useCallback的优化前提是依赖项稳定,但你之前每次渲染都生成新的Promise,导致Suspense状态反复变化——即使组件被memo包裹,内部依赖的Promise实例变更仍会触发重渲染和Suspense的挂起/恢复流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 05:59:51