Next.js 这些都是错误写法?来看看初学者容易踩的坑

262 阅读2分钟

马上推出的 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中,我们需要将ssrcsr真正区分开,不可以不做区分就使用(第一种),也不可以做条件判断渲染(第二种),正确的做法是通过useEffect来隔绝区分ssrcsr内容

"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() {
    ...
}