使用 nextjs App Router 进行服务器端渲染和动态客户端

Rya*_*ill 7 reactjs next.js

我在 NextJs 中经常使用的一种模式是渲染服务器端的所有内容(包括数据获取),然后过渡到动态客户端渲染。人为的例子:

export async function getServerSideProps() {
  const res = await fetch(`api/myData`)
  const data = await res.json()

  return {
    props: { initialData: [data] }
  }
}

export default function About({ initialData }) {
  const [data, setData] = useState(initialData)

  const addItem = () => {
    const item = "foo"
    const res = await fetch('/api/addData')
    setData([...data, JSON.parse(res.body).item])
  }

  return (
    <div>
      {data.map(item => (<div>{item}</div>))}
      
      <button onClick={addItem}>Add Item</button>
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

我不知道如何通过构建 NextJs 的新 App Router 风格获得相同类型的功能。谁能告诉我我缺少什么?

ale*_*izl 9

让我们分步骤来分解:

  1. 您想要initalData动态获取服务器端,这意味着您需要在服务器组件中获取数据,我认为该page.tsx组件是实现此目的的一个很好的地方,因此示例页面组件是:

    export default async function Page() {
      const res = await fetch(`api/myData`, {cache: 'no-store'});
      const data = await res.json();
    
      return <About initialData={[data]} />
    }
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,fetchcache: 'no-store',这是选择动态渲染所必需的,因为静态渲染是默认的,这也可以通过 来实现revalidate: 0

  2. 您需要制作<About />一个客户端组件才能使用useState等。因此您需要'use client'在 About 组件文件的顶部添加。

要记住的一件事是,在现实世界的应用程序中,您可能希望静态渲染页面,解决方案是将我们所做的封装到单独的服务器组件中,并让该服务器组件获取数据并动态渲染,而不是整个页面组件。

还涉及客户端和服务器组件之间的动态。客户端组件实际上是在服务器中预渲染的(html/css 和一个小的 js 包),但它们也需要一个无法在服务器中运行的 js 负载,如果你仔细想想,在useState服务器中运行是没有意义的,因为状态存在于用户浏览器中,更不用说onClick在服务器中拥有侦听器了。当 nextjs 预渲染客户端组件时,它会发回渲染的 html/css/server js 以及需要在客户端中执行的客户端 js 有效负载。另一方面,服务器组件不需要客户端 js,因此服务器只返回 html/css 和一小段 js。在您的原始示例中,该组件getServerSideProps在服务器中执行,但该组件具有客户端负载,就像具有新应用程序文件夹路由器的<About />组件一样。当前不支持具有客户端代码(如并在服务器中呈现 100% use client)的组件,并且这种组件的意义为零。关于 html 和 css,正如我之前所说,它最初也是在服务器中为客户端组件预渲染的。您可以在这里阅读更多相关信息https://nextjs.org/docs/getting-started/react-essentials#client-componentsuseStateonClick