Next13 新功能整理

系统要求:

  • Node.js 14.6.0 或更新版本 (测试版本 Node.js v16.8)
  • 支持 Mac OS、Windows(包括 WSL)和 Linux

安装:

npx create-next-app@latest --typescript 
# or yarn create next-app --typescript 
# or pnpm create next-app --typescript

React 服务器组件

服务端组件

Next13 支持 React 服务器组件,服务器组件能够在服务器端执行和渲染 React 组件,以前会影响客户端上 JavaScript 包大小的大型依赖项现在可以完全保留在服务器上,从而提高性能。
当一个路由被加载时,Next.js和React runtime将被加载,它是可缓存的,而且大小可预测。这个运行时不会随着你的应用程序的增长而增加大小。此外,运行时是异步加载的,使你的HTML从服务器上被逐步增强到客户端上。
只有当客户端的交互性通过客户端组件在你的应用程序中使用时,才会添加额外的JavaScript。
个人理解:
图片[1]-Next13 新功能整理-烟雨网
渲染服务器组件实际上是一个 API 调用,以获取序列化的虚拟 DOM,然后在浏览器中实现它。
最重要的是,服务器组件用于呈现非交互式内容,因此没有事件处理程序、没有 React 勾子,也没有仅限浏览器的 API
最显着的好处是可以自由访问服务器组件中的任何后端资源和机密。它更安全(数据不会泄漏)和更快(代码不会泄漏)。

客户端组件

客户端组件是在客户端渲染的。
客户端组件也可以在服务器上预渲染,并在客户端进行水合化。
要使用客户端组件,在app中创建一个文件,并在文件的顶部(在任何导入之前)添加 “use client” 。

'use client'

import { useEffect } from 'react'

export default function Client() {
  console.log(
    'Client page rendering: this should only be printed on the server during ssr, and client when routing'
  )

  useEffect(() => {
    console.log('Client component rendered')
  })

  return (
    <div>
      <h1>Client Page</h1>
      {/* Uncommenting this will result in an error complaining about inconsistent
            rendering between client and server, which is very true */}
      {/* <p>My secret env: {process.env.MY_SECRET_ENV}</p> */}

      <br></br>
      <p>Render log and useEffect log should be printed in browser console</p>
    </div>
  )
}

当页面首次加载时,它是由 SSR 渲染的;因此您应该在服务器控制台中看到第一个日志;在客户端路由期间,两条日志消息都将出现在浏览器控制台中。

Next.js 13 路由系统

增加 app 目录(测试版本)

目前还在测试阶段,需要在 next.config.js 中开启才能使用, 默认情况下app下的所有文件都属于服务器组件:

/** @type {import('next').NextConfig} */
const nextConfig = {
    experimental: {
        appDir: true,
    },
}

module.exports = nextConfig
route Next 12 Next 13
/ pages/index.js app/page.js
/blog pages/blog.js app/blog/page.js
/blog/new pages/blog/new.js app/blog/new/page.js

另外,在服务器启动的时候 Next 会在 app 目录下检测是否有根布局组件,如果没有会帮自动创建。
Next.js 13引入了一个全新的 app 文件夹,其中有一个完全翻新的路由系统。
它包括许多改进,其中最好的礼物是新的布局机制。
只要它们的路由不发生冲突,app文件夹可以与旧的页面文件夹共存,这使你可以逐步采用。

新的文件夹结构

app 文件夹要求每个路由都是一个文件夹,使定义路由更加明确。
一个路由文件夹通常包含以下路由文件(有.js|.ts|.jsx|.tsx后缀)。

  • page – 为这个路由提供特定的用户界面。
  • layout – 为这个路由和所有后代路由提供布局UI。
  • loading – 当路由的服务器组件正在加载时,提供一个加载的用户界面
  • error – 为处理此路由内和下的错误提供UI(除非由子层的另一个错误路由处理)。

Layout and nesting

在以前的版本中:

// pages/index.js

export default function Page() {
  return (
    /** Your content */
    <div>Your content</div>
  )
}

Page.getLayout = function getLayout(page) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}

// pages/_app.js
export default function MyApp({ Component, pageProps }) {
  // 使用在页面级别定义的布局(如果可用)
  const getLayout = Component.getLayout || (page => page)
  return getLayout(<Component {...pageProps} />)
}

使用Next.js 13

新的路由系统使 “layout “成为一流的公民。
在app下的任何一级文件夹(即任何一级路由),都可以使用layout.tsx来明确定义一个容器组件。
这个容器组件将自动环绕该文件夹内和下的所有页面。
如果在不同级别有多个layout.tsx组件,就会自动构建一个包裹的层次结构。
图片[2]-Next13 新功能整理-烟雨网
layout 官方文档

错误处理

React有一个Error Boundaries的概念,用于以结构化的方式捕获错误。
Next.js的路由文件夹自然形成了一个组件层次结构。
为什么我们不发明一个公约来处理任何层次的路由的错误呢?
这就是error.tsx文件的作用。它只不过是在中包装下级组件树的语法糖。
图片[3]-Next13 新功能整理-烟雨网
官方文档

Next.js 13 数据获取

在 Next.js 13 之前,页面级数据获取模式非常简单

  • 如果页面(大部分)是静态的,使用 getStaticProps 获取数据,以便在构建时(和ISR时)进行获取。
  • 如果页面是动态的,使用 getServerSideProps 在服务器端获取数据。
  • 对于依赖于用户交互的数据,在 useEffect 页面呈现后在钩子中在客户端进行抓取。

这已在 Next.js 13 中完全翻新(如果您选择实验性功能)。但在我们看到新东西之前,让我们反思一下旧世界的问题。

旧模式的问题

  • 看起来不自然
export default function Page({ data }) {
  // Render data...
}

export async function getServerSideProps() {
  const res = await fetch(`https://.../data`)
  const data = await res.json()
  return { props: { data } }
}

你必须严格按照约定来书写代码。

  • Prop drilling

引发props嵌套传递问题,层层传递 , 解决办法是使用 Context API 或者 组件组合模式 ,但这要么会阻碍组件的可重用性,要么需要仔细设计它们。

  • 不成功便成仁 (要么有要么无)

当使用 getServerSideProps 时,无论页面加载是由浏览器重载还是由客户端路由触发,新的页面内容都不会显示,直到数据获取完全完成(异步getServerSideProps函数解析)。如果页面同时包含 “快速数据 “和 “慢速数据”,这可能是个问题。
例如,数据仪表板是一个典型的场景:一些卡片可以瞬间加载,而另一些则需要很多秒。

Next.js 13中修改了什么?

Next.js 13中引入的新数据获取模式放弃了之前你所熟悉的一切:

  • getStaticProps
  • getServerSideProps

甚至对于客户端的获取,也有一个新的使用钩子,有可能取代useEffect中的旧的获取方式。

异步服务器组件

在旧世界里,组件是同步的,你不能在组件的顶层等待。在Next.js 13中,所有组件默认为 “服务器”,可以是异步的。最后,我们可以在React组件中使用我们熟悉的async/await语法。
这使得数据的获取变得更加容易和灵活。最重要的是,你可以将服务器端的获取逻辑分布到多个地方,并将它们与使用数据的组件搭配在一起。
示例:

// app/server-async-fetching/page.tsx
import { Suspense } from 'react'
import Quote from '../../components/server/quote'

export default function AsyncLoading() {
  return (
    <>
      <h1>Server Component Async Fetching</h1>
      <div className="flex flex-col gap-4 w-full h-full">
        {/* @ts-ignore */}
        <Quote />
        {/* @ts-ignore */}
        <Quote slow={true} />
      </div>
    </>
  )
}

// lib/quote.ts
import sleep from 'sleep-promise'

export async function getQuote(delay = 0) {
  if (delay) {
    await sleep(delay)
  }
  console.log('Getting quote')
  return (await fetch('https://api.quotable.io/random?tags=technology')).json()
}

// components/server/Quote.tsx
import { getQuote } from '../../lib/quote'
import os from 'os'

export default async function Quote({ slow }: { slow?: boolean }) {
  const quote = await getQuote(slow ? 2000 : 0)
  return (
    <div className="container border border-blue-600 rounded p-4">
      <p>
        {slow ? 'Slow' : 'Fast'} component rendered on{' '}
        <span className="text-orange-600">${os.hostname()}</span>
      </p>
      <blockquote className='"text-xl italic font-semibold text-gray-900 p-4'>
        {quote.content}
      </blockquote>
    </div>
  )
}

// app/server-async-fetching/Loading.tsx
export default function Loading() {
  return <p>Loading...</p>
}



以上代码,在数据没有请求回来之前,Loading 组件一直展示到客户端以及服务端组件都可以渲染为止,这也是典型的 不成功便成仁(all-or-nothing) 🥶 。
我们可以通过在组件周围添加 来通过一个小的修复来改进它。 Suspense 最初是由 React 添加的,用于支持代码拆分;现在它可用于为尚未解析的异步组件提供后备 UI,因此它们可以无阻塞地呈现:

import { Suspense } from 'react'
import Quote from '../../components/server/quote'

export default function AsyncLoading() {
  return (
    <>
      <h1>Server Component Async Fetching</h1>
      <div className="flex flex-col gap-4 w-full h-full">
        <Suspense fallback={<p>Fast component loading...</p>}>
          {/* @ts-ignore */}
          <Quote />
        </Suspense>

        <Suspense fallback={<p>Slow component loading...</p>}>
          {/* @ts-ignore */}
          <Quote slow={true} />
        </Suspense>
      </div>
    </>
  )
}

现在好多了。😊 你可以看到,页面及其两个子组件的渲染是完全异步的。
React已经扩展了Suspense的功能,以支持任意的异步操作。它现在可以完美地与异步服务器组件协同工作。Suspense最酷的地方在于,”取消暂停 “一个组件不需要额外的API请求或WebSocket连接。相反,新的页面内容是通过向HTML文档追加虚拟DOM(用

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容