马上推出的 React.19 跟Next强绑定了,这也预示着Next.js将是每个React开发者绕不开的关卡了。
Next.js相较传统 React 新增了ssr(server side render)的概念,简单说就是在服务端预先渲染了一遍。听着简单,但实际上就是因为新增了这一小小的概念,使我们的写法需要注意很多小细节,下面一起来看看吧
1. window
我们知道,ssr是没有window对象的,因此这个组件需要csr。
你可能会认为在顶部"use client"便能万事大吉,但事实上,这部分代码仍然会在服务端执行,于是便会引发window is not definederror
"use client"
// bad
export default function ClientExample() {
const { innerHeight: height } = window
return <p>Window height is {height}</p>
}
我们很容易想到以下写法,这是新手初期常犯的错误。这样会引起Text content does not match server-rendered HTML这样相似的水合错误(hydration)
"use client"
// bad
export default function ClientExample() {
const height = typeof window !== 'undefined'
? window.innerHeight
: "not available"
return <p>Window height is {height}</p>
}
在Next.js中,我们需要将ssr和csr真正区分开,不可以不做区分就使用(第一种),也不可以做条件判断渲染(第二种),正确的做法是通过useEffect来隔绝区分ssr和csr内容
"use client"
import { useState, useEffect } from 'react'
// good
export default function ClientExample() {
const [height, setHeight] = useState(0)
useEffect(() => {
setHeight(window.innerHeight)
}, [])
return <p>Window height is {height}</p>
}
2. use client
我们知道"use client"是客户端渲染的标志,那么我们需要对每个客户端组件都加上"use client"吗?
并不是,当我们的父组件是客户端组件时,子组件也自然是客户端渲染了,自然也不必要加"use client"
// index.jsx
"use client"
import Counter from './Counter.jsx'
export default function ClientExample({ children }) {
return (
<>
// Counter 组件不用写 use client 自动为客户端组件
<Counter/>
// 这个children不一定,可以是客户端也可以是服务端组件
{children}
</>
)
}
// counter.jsx
// 不用写 use client
import { useState } from 'react'
export default function Counter() {
...
}