如何阻止 Next.js 在使用“use client”指令时两次运行客户端代码或无限期挂起?

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

问题

我有一个场景,我必须使用

'use client'
指令,因为我的项目使用Chakra UI并且它们的组件无法在服务器中渲染。

当我尝试运行此示例代码时:

// app/page.tsx

export async function getData() {
  const side = typeof window === 'undefined' ? 'server' : 'client'
  console.log(`I am running ${side} side!`)
  const dados = await Promise.resolve([{ name: 'Hi' }, { name: 'Hello' }])
  return dados
}

export default async function Home() {
  const data = await getData()
  return (
    <ul>
      {data.map(({ name }: any) =>
        <li key={name}>{name}</li>
      )}
    </ul>
  )
}

我在运行下一个开发服务器的终端中收到了预期的输出:

I am running server side!

但是当我在文件顶部添加

'use client'
指令时,我在浏览器控制台中收到此重复消息:

I am running client side!   (2)

我知道

'use client'
指令强制所有函数在浏览器中运行但我不明白为什么它们运行两次。 这是一个问题,因为在我的实际项目中,等待 Promise 的行向后端发出请求,而 Next.js 无法缓存这些请求,导致重复的请求命中 API。

我尝试了什么

多个文件

我尝试将

getData
函数移动到另一个文件并运行该项目:

// app/otherFile.ts

export async function getData() {
  const side = typeof window === 'undefined' ? 'server' : 'client'
  console.log(`I am running ${side} side!`)
  const dados = await Promise.resolve([{ name: 'Hi' }, { name: 'Hello' }])
  return dados
}
// app/page.tsx

import { getData } from './otherFile'

export default async function Home() {
  const data = await getData()
  return (
    <ul>
      {data.map(({ name }: any) =>
        <li key={name}>{name}</li>
      )}
    </ul>
  )
}

令我惊讶的是,我在我的下一个开发服务器中看到了这个

I am running server side!

在我的浏览器控制台中

I am running client side!   (2)

,在我的真实应用程序中,每次页面重新加载都会点击我的 API 3 次。

实验服务器操作

我还尝试在我的

next.config.js
中启用“实验服务器操作”,并在
'use server'
中添加
app/otherFile.ts
指令。当我尝试重新加载页面时,它无限期地挂起并且不显示任何输出。

后续步骤?

为什么会发生这种情况以及如何避免这种行为?这可能吗?

我正在使用 Next.js 13.4.4 和 React 18.2.0。

reactjs next.js react-hooks next.js13 async-components
3个回答
3
投票

虽然双重渲染在开发过程中可能不方便,但在部署时它不应该影响应用程序的功能或性能。

该问题可能与 React 18 有关。您可以在这里查看:https://github.com/vercel/next.js/issues/35822

您可以尝试通过将reactStrictMode选项设置为true或false来在next.config.js文件中启用或禁用严格模式。

我希望这些信息会有所帮助。


0
投票

发生这种情况可能是因为 Next.js 运行您的页面两次,一次在服务器上,一次在浏览器中。为了避免重复 API 调用,我们可以尝试使用 React 的

useEffect
钩子来确保
getData
函数只被调用一次。这是一个例子:

import { useEffect, useState } from 'react'
import { getData } from './otherFile'

export default function Home() {
const [data, setData] = useState([])

useEffect(() => {
  const fetchData = async () => {
  const response = await getData()
    setData(response)
}
fetchData()
}, [])

return (
 <ul>
   {data.map(({ name }) => <li key={name}>{name}</li>)}
 </ul>
  )
}

希望这有帮助!如果您有更多问题,请随时联系!


0
投票

您可以通过在 next.config.mjs 中禁用它来测试是否是 React Strict 模式导致双重渲染

const nextConfig = {
compiler: {
  styledComponents: {
    // Enabled by default.
    cssProp: true,
  },
},
reactStrictMode: false

};

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