我有一个场景,我必须使用
'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。
虽然双重渲染在开发过程中可能不方便,但在部署时它不应该影响应用程序的功能或性能。
该问题可能与 React 18 有关。您可以在这里查看:https://github.com/vercel/next.js/issues/35822
您可以尝试通过将reactStrictMode选项设置为true或false来在next.config.js文件中启用或禁用严格模式。
我希望这些信息会有所帮助。
发生这种情况可能是因为 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>
)
}
希望这有帮助!如果您有更多问题,请随时联系!
您可以通过在 next.config.mjs 中禁用它来测试是否是 React Strict 模式导致双重渲染
const nextConfig = {
compiler: {
styledComponents: {
// Enabled by default.
cssProp: true,
},
},
reactStrictMode: false
};