试着修正代码,程序会主动热更新,绝大多数次数更新时刻都很快,但偶尔有几次更新时刻却很长,图片中有一处需求 16s(我运用的是 Mac M1),这其中的原因就不得而知了,尤大也发布了测评,运用 1000 个节点来比照更新速度,数据显现:根组件与 vite 时刻简直相同,叶子节点比 vite 快 68%,与官方称比 vite 快 10 倍相差甚远。当然现在 Turbopack 还处于 alpha 阶段,等待 Turbopack 可以赶快推出正式版。
Vite 依靠于浏览器的原生 ES Modules 体系,不需求打包代码,这种办法只需求转化单个 JS 文件,呼应更新很快,可是假如文件过多,这种办法会导致浏览器很多级联网络恳求,会导致发动时刻相对较慢。所以作者挑选同 webpack 一样办法,打包,可是运用了 Turbo 构建引擎,一个增量回忆化结构,永远不会重复相同的工作。
SSR 处理了白屏时刻过长的问题和 SEO 的问题,但也并不是完美的,过多的恳求会导致服务端呼应时刻变长,“灌水”(Hydrate)的过程也会导致客户端代码量的添加。
所谓的流便是通过 script 动态回来最小 html,而且刺进到正确的方位,页面中假如有多个 Suspense,是没有先后顺序的,React Server Components 是并行的。
以上内容在《New Suspense SSR Architecture in React 18》 中可以找到,而要搭建 react 流烘托的架构相比照较复杂,咱们可以看 gaearon dan 的 demo,而 Next.js 13 只需求在 app 目录下,依照约好的文件称号写,就可以主动完成 React Server Components。
加入了一个新的包,可以在构建时直接引证 google 字体和本地字体,完成字体的保管和预加载,这点对英文网站很有用,中文网站一般不加载字体,图标主张运用 svg。
本文首要结合了 Next13 官网博客 摘取了部分内容,结合笔者对 Next.js 的了解和分析,介绍了其变动、运用办法,以及其改动原因, Next13 这次更新首要与 React server component 深度结合,在”用户体会、可维护性、功能”这几个方面都带来了巨大的提高,本认为 React 的 Server component 还遥不可及,但 Next13 却让咱们触手可及, Next13 也将成为升级 React18 的首选结构,未来前后端并行的开发形式或许可以成为主流,这也将是对前端开发者的一个挑战。
这是发动后的界面,这个 demo 不是一个简单的页面,而是一个包含了深度嵌套路由的比方。
下图我开发时的截图,Turbopack 直接在命令行中打印出了构建时刻,咱们看到发动时刻只需求 2.3ms
试着修正代码,程序会主动热更新,绝大多数次数更新时刻都很快,但偶尔有几次更新时刻却很长,图片中有一处需求 16s(我运用的是 Mac M1),这其中的原因就不得而知了,尤大也发布了测评,运用 1000 个节点来比照更新速度,数据显现:根组件与 vite 时刻简直相同,叶子节点比 vite 快 68%,与官方称比 vite 快 10 倍相差甚远。当然现在 Turbopack 还处于 alpha 阶段,等待 Turbopack 可以赶快推出正式版。
Turbopack 特点
- 开箱即用 TypeScript, JSX, CSS, CSS Modules, WebAssembly 等
- 增量核算: Turbopack 是树立在 Turbo 之上的,Turbo 是根据 Rust 的开源、增量回忆化结构,除了可以缓存代码,还可以缓存函数运转成果。
- 懒编译:例如,假如拜访 localhost:3000,它将仅打包
pages/index.jsx
,以及导入的模块。
为什么不挑选 Vite 和 Esbuild?
Vite 依靠于浏览器的原生 ES Modules 体系,不需求打包代码,这种办法只需求转化单个 JS 文件,呼应更新很快,可是假如文件过多,这种办法会导致浏览器很多级联网络恳求,会导致发动时刻相对较慢。所以作者挑选同 webpack 一样办法,打包,可是运用了 Turbo 构建引擎,一个增量回忆化结构,永远不会重复相同的工作。
Esbuild 是一个十分快速的打包工具,但它并没有做太多的缓存,也没有 HMR(热更新),所以在开发环境下不适用。
为什么要改根据文件的路由体系
Next 13 另一个比较大的改动是根据文件的路由体系,添加了一个 app
目录,每一层路由有必要建一个文件夹,在该文件夹中树立 page.tsx
作为该路由主页面
而在 Next.js 12(以及以下)对应的路由体系,是一切路由文件都写在 pages
目录下,每个文件都会生成一个路由,很明显是这种办法更加简练。
那么,Next.js 为什么要改根据文件的路由体系呢?
首要有以下 3 点原因:
- 完成嵌套路由和耐久化缓存
- 支撑 React 18 中的 React server Component,完成 Streaming(流烘托)
- 完成代码目录分组,将当时路由下的测验文件、组件、款式文件友好地放在一起,防止大局查找
Next.js 12 中 Layout 完成办法
Tailwindcss 的作者 Adam Wathan 早在 2019 年就写过一篇博客,关于 Next.js 如何完成耐久化缓存
其中有个demo可以很好的说明 next.js 不能完成耐久化缓存,咱们可以在 codesandbox 中体会。
完成办法是每个 page 页面直接引证 components 文件下的导航组件,当点击横向滚动条后边的导航页面,会导致整个页面都改写,然后没有记录滚条的方位。
他处理办法是,需求通过往 Page 页面函数上添加静态办法getLayout
来完成,概况代码可以看这个比方。
import SiteLayout from '../../components/SiteLayout'
import { getLayout } from '../../components/AccountSettingsLayout'
const AccountSettingsBasicInformation = () => <div>{/* ... */}</div>
AccountSettingsBasicInformation.getLayout = getLayout
export default AccountSettingsBasicInformation
比方上面比方中的账户设置—->基本信息
页面代码,是在 Page 页面中绑定 getLayout
静态办法,getLayout
回来页面的公共导航组件。
在 _app.tsx
中调用 getLayout
办法,然后差异各个页面的 layout
布局不同。
import React from 'react'
import App from 'next/app'
class MyApp extends App {
render() {
const { Component, pageProps, router } = this.props
const getLayout = Component.getLayout || (page => page)
return getLayout(<Component {...pageProps}></Component>)
}
}
export default MyApp
假如你也有之前的 Next 项目,也需求完成耐久化缓存,可以参阅这个比方。
app 文件夹下的约好式路由
Next13 新增了 app 文件夹
来完成约好式路由,完美地完成了耐久化缓存,以下是官方 with-turbopack
项目下部分页面结构
./app
├── GlobalNav.tsx
├── layout.tsx
├── page.tsx
├── layouts
│ ├── CategoryNav.tsx
│ ├── [categorySlug]
│ │ ├── SubCategoryNav.tsx
│ │ ├── [subCategorySlug]
│ │ │ └── page.tsx
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── template.tsx
│ ├── layout.tsx
│ ├── page.tsx
│ └── template.tsx
对应的页面效果如下图
咱们看到每个文件下都有 3 个文件 layout.tsx
、page.tsx
、template.tsx
、
-
layout.tsx
该路由下的公共导航,切换路由时,不会改写,咱们可以看箭头处的 Count 组件,并没有改写
-
template.tsx
该路由下的公共部分,切换路由时,会改写
-
page.tsx
该路由的主页面
当咱们点击导航时分,页面上改写部分边框会高亮闪耀,咱们可以很好地了解代码目录结构组织与页面呈现的路由和烘托。
在 app 目录下每个文件夹下,还可以有 loading.tsx
、error.tsx
-
loading.tsx
该路由的主页面在异步烘托中,会显现的 loading 组件的内容;例如咱们可以用它来写骨架屏(Skeleton)
-
error.tsx
该路由的页面烘托出错,会显现该页面,也便是封装了 React 的 ErrorBoundary。
以上除了 page.tsx
其他文件都是可选的,除了这些约好称号的文件外,咱们可以树立任意文件,比方 components.tsx
、 test.tsx
等自定义文件。app 目录可以很好地将页面、组件、测验文件放在一起,办理代码目录,防止开发时大局查找。
路由分组
app 同层级目录下还支撑多个 layout
, 运用 (文件夹)
区别,(文件夹)
不会体现在路由上,仅仅单纯用来做代码分组。
./app
├── (checkout)
│ ├── checkout
│ │ └── page.tsx
│ ├── layout.tsx
│ └── template.tsx
├── (main)
│ ├── layout.tsx
│ ├── page.tsx
│ └── template.tsx
比方官方 playground 中关于电子商务的比方,main
和 checkout
的 layout 是不同的,可以根据完成功用自定义分组代码目录。
React Server Components
在 app 目录下的组件默许都是 React Server Components,那么 React Server Components 有什么优势呢?
这里有几个概念
-
CSR:一切前端打包到前端,通常会引起浏览器加载 JavaScript 过大,然后导致首屏白屏时刻过长
-
SSR:数据在服务端恳求,通过 renderToString
办法将字符串 DOM 结构输出给浏览器,此时浏览器还不能交互,React 不能办理现已存在的 DOM,需求从头履行一遍,这个过程叫“灌水”(Hydrate)。Next12 getServerSideProps
的烘托办法也便是 SSR。
SSR 处理了白屏时刻过长的问题和 SEO 的问题,但也并不是完美的,过多的恳求会导致服务端呼应时刻变长,“灌水”(Hydrate)的过程也会导致客户端代码量的添加。
比方一个传统的博客页面选用 Next12 的办法运用getServerSideProps
的办法烘托,那么就需求等 3 个接口悉数回来才可以看到页面。
export async function getServerSideProps() {
const list = await getBlogList()
const detail = await getBlogDetail()
const comments = await getComments()
return { props: { list,detail,comments } }
}
- React Server Components ( RFC ) 与传统的 SSR 不同,优点是拥有流式 HTML 和挑选性灌水
React Suspense
API 解锁了 React 18 中的两个首要 SSR 功用:
比方上面的博客实例,谈论接口查询速度较慢,就可以运用 Suspense
完成流烘托。
import { lazy } from 'react';
const Comments = lazy(() => import('./Comments.js'));
return (
<Layout>
<NavBar />
<Sidebar />
<RightPane>
<Post />
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
</RightPane>
</Layout>
)
如图所示
- 灰色部分代表 HTML 字符串回来
- loading 状况表示当时部分还在恳求
- 绿色部分代表灌水成功,页面可以交互
所谓的流便是通过 script 动态回来最小 html,而且刺进到正确的方位,页面中假如有多个 Suspense,是没有先后顺序的,React Server Components 是并行的。
以上内容在《New Suspense SSR Architecture in React 18》 中可以找到,而要搭建 react 流烘托的架构相比照较复杂,咱们可以看 gaearon dan 的 demo,而 Next.js 13 只需求在 app 目录下,依照约好的文件称号写,就可以主动完成 React Server Components。
完成流烘托
除了 app 目录下嵌套路由部分 next.js 会帮咱们默许选用 React Server Components,咱们在 page 页面中,也可以完成。
完成办法也很简单,组件外层运用 Suspense
import { SkeletonCard } from '@/ui/SkeletonCard';
import { Suspense } from 'react';
import Description from './description';
export default function Posts() {
return (
<section>
<Suspense
fallback={
<div className="w-full h-40 ">
<SkeletonCard isLoading={true} />
</div>
}
>
<Description />
</Suspense>
</section>
);
}
组件数据恳求运用 use
API,就可以完成流烘托了。
import { use } from 'react';
async function fetchDescription(): Promise<string> {
return fetch('http://www.example.com/api/data').then((res)=>res.text())
}
export default function Description() {
let msg = use(fetchDescription());
return (
<section>
<div>{msg}</div>
</section>
);
}
运用场景
从官方的 playground 中看,在一些恳求较慢的接口,比方电商网站中的价格核算,若要运用服务端烘托,就可以运用 server Component。
服务端组件和客户端组件
Next.js 最大的优势便是咱们只需求一个工程,就可以搞定前端工程和后端工程,哪些是前端代码和哪些是后端代码,Next.js 在打包的时分就会帮咱们主动区别,这需求开发者清楚地了解,自己写的代码哪些是在服务端履行,哪些是在客户端履行。
Next12 区别
咱们知道 Page 函数都是在服务端履行的,包括 getServerSideProps
、getStaticPaths
、getStaticProps
,那么假如需求在客户端履行有以下 2 种办法;
- 在
useEffect
、 onChange
等回调函数中运用,比方下面比方,动态加载了 fuse.js
,完成模糊搜索。
import { useState } from 'react'
const names = ['Tim', 'Joe', 'Bel', 'Lee']
export default function Page() {
const [results, setResults] = useState()
return (
<div>
<input
type="text"
placeholder="Search"
onChange={async (e) => {
const { value } = e.currentTarget
// Dynamically load fuse.js
const Fuse = (await import('fuse.js')).default
const fuse = new Fuse(names)
setResults(fuse.search(value))
}}
/>
<pre>Results: {JSON.stringify(results, null, 2)}</pre>
</div>
)
}
- 假如依靠了外部组件,或许 window 目标,可以运用
next/dynamic
而且设置 ssr
为 false
import dynamic from 'next/dynamic'
const DynamicHeader = dynamic(() => import('../components/header'), {
ssr: false,
})
Next13 区别
在 Next13 中 , 在 app 目录下,如要运用 useState
等状况办理的 hook,那么该组件只在客户端履行,需求在首行加入 'use client'
指令。
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
该区别服务端组件和客户端组件,下表列出了常用运用场景
运用场景 |
服务端组件 |
客户端组件 |
fetch 恳求数据。 |
✅ |
[⚠️] |
拜访后端资源(直接) |
✅ |
❌ |
在服务器上保存灵敏信息(拜访令牌、API 密钥等) |
✅ |
❌ |
坚持对服务器的很多依靠/减少客户端 JavaScript |
✅ |
❌ |
添加交互和事情侦听器(onClick() ,onChange() 等) |
❌ |
✅ |
运用状况和生命周期效果(useState() ,useReducer() ,useEffect() , 等) |
❌ |
✅ |
运用仅限浏览器的 API(window) |
❌ |
✅ |
运用依靠于状况、效果或仅浏览器 API 的自定义 hooks |
❌ |
✅ |
运用React 类组件
|
❌ |
✅ |
数据恳求
运用 react 的 use 函数加 fetch API 来完成:静态站点生成(SSG)、服务器端烘托(SSR)和增量静态再生(ISR)
在 Page 页面运用 fetch:
import { use } from 'react';
async function getData() {
const res = await fetch('...');
const name: string = await res.json();
return name;
}
export default function Page() {
const name = use(getData());
return '...';
}
fetch 的缓存策略
fetch(URL, { cache: 'force-cache' });
fetch(URL, { cache: 'no-store' });
fetch(URL, { next: { revalidate: 10 } });
运用这种办法的优点是,当恳求数据的添加,打包后前端 JavaScript 的大小不会添加。
新的 next/image
咱们知道在 Next.js 12 之前,运用 <img>
标签,eslint 会有一个正告,提示咱们有必要运用 next/image
组件, 因为 next/image
帮咱们做了几点优化
- 主动优化图片格局
- 主动缩放图片大小
- 运用
Intersection Observer API
完成懒加载
所以 image 有必要加上 width
和 height
参数
新的 Next/image 运用了浏览器的 lazy-loading 代替了 Intersection Observer API
默许情况下需求 alt 符号,因而减少了客户端 JavaScript 代码,当然这个属性对浏览器要求较高,要求 chrome 77+。
import Image from 'next/image';
import avatar from './lee.png';
function Home() {
return <Image alt="leeerob" src={avatar} placeholder="blur" />;
}
@next/font
加入了一个新的包,可以在构建时直接引证 google 字体和本地字体,完成字体的保管和预加载,这点对英文网站很有用,中文网站一般不加载字体,图标主张运用 svg。
加载谷歌字体
import { Inter } from '@next/font/google';
const inter = Inter();
<html className={inter.className}>
加载本地字体
import localFont from '@next/font/local';
const myFont = localFont({ src: './my-font.woff2' });
<html className={myFont.className}>
next/link
主动加上 <a>
标签。
Next.js 12: 需求<a>
包裹
import Link from 'next/link'
<Link href="/about">
<a>About</a>
</Link>
Next.js 13: <Link>
不需求 <a>
<Link href="/about">
About
</Link>
小结
本文首要结合了 Next13 官网博客 摘取了部分内容,结合笔者对 Next.js 的了解和分析,介绍了其变动、运用办法,以及其改动原因, Next13 这次更新首要与 React server component 深度结合,在”用户体会、可维护性、功能”这几个方面都带来了巨大的提高,本认为 React 的 Server component 还遥不可及,但 Next13 却让咱们触手可及, Next13 也将成为升级 React18 的首选结构,未来前后端并行的开发形式或许可以成为主流,这也将是对前端开发者的一个挑战。
以上便是本文的悉数内容,关于 Next13 你学会了吗?欢迎在谈论区留言讨论,文中若有不正之处,万望奉告。
文章为稀土技术社区首发签约文章,14 天内禁止转载,14 天后未获授权禁止转载,侵权必究!
前言
上周发布了 Next.js 的一个全新的版别 13,它带来了全新的理念(server component),作为一名 Next.js 的爱好者,咱们有必要从头学习和知道下它。
Turbopack
首先是最引进注目的,在 Next13 中加入了全新的打包工具 Turbopack, 它是出自 Webpack 作者 TobiasKoppers 之手,官方描绘是:开发时更新速度比 Webpack 快 700 倍、比 Vite 快 10 倍,是不是有点刻不容缓,想要熟手体会了呢?咱们直接运用官方提供的 cli 创建一个 Next.js 工程。
npx create-next-app
这是发动后的界面,这个 demo 不是一个简单的页面,而是一个包含了深度嵌套路由的比方。
下图我开发时的截图,Turbopack 直接在命令行中打印出了构建时刻,咱们看到发动时刻只需求 2.3ms
试着修正代码,程序会主动热更新,绝大多数次数更新时刻都很快,但偶尔有几次更新时刻却很长,图片中有一处需求 16s(我运用的是 Mac M1),这其中的原因就不得而知了,尤大也发布了测评,运用 1000 个节点来比照更新速度,数据显现:根组件与 vite 时刻简直相同,叶子节点比 vite 快 68%,与官方称比 vite 快 10 倍相差甚远。当然现在 Turbopack 还处于 alpha 阶段,等待 Turbopack 可以赶快推出正式版。
Turbopack 特点
- 开箱即用 TypeScript, JSX, CSS, CSS Modules, WebAssembly 等
- 增量核算: Turbopack 是树立在 Turbo 之上的,Turbo 是根据 Rust 的开源、增量回忆化结构,除了可以缓存代码,还可以缓存函数运转成果。
- 懒编译:例如,假如拜访 localhost:3000,它将仅打包
pages/index.jsx
,以及导入的模块。
为什么不挑选 Vite 和 Esbuild?
Vite 依靠于浏览器的原生 ES Modules 体系,不需求打包代码,这种办法只需求转化单个 JS 文件,呼应更新很快,可是假如文件过多,这种办法会导致浏览器很多级联网络恳求,会导致发动时刻相对较慢。所以作者挑选同 webpack 一样办法,打包,可是运用了 Turbo 构建引擎,一个增量回忆化结构,永远不会重复相同的工作。
Esbuild 是一个十分快速的打包工具,但它并没有做太多的缓存,也没有 HMR(热更新),所以在开发环境下不适用。
为什么要改根据文件的路由体系
Next 13 另一个比较大的改动是根据文件的路由体系,添加了一个 app
目录,每一层路由有必要建一个文件夹,在该文件夹中树立 page.tsx
作为该路由主页面
而在 Next.js 12(以及以下)对应的路由体系,是一切路由文件都写在 pages
目录下,每个文件都会生成一个路由,很明显是这种办法更加简练。
那么,Next.js 为什么要改根据文件的路由体系呢?
首要有以下 3 点原因:
- 完成嵌套路由和耐久化缓存
- 支撑 React 18 中的 React server Component,完成 Streaming(流烘托)
- 完成代码目录分组,将当时路由下的测验文件、组件、款式文件友好地放在一起,防止大局查找
Next.js 12 中 Layout 完成办法
Tailwindcss 的作者 Adam Wathan 早在 2019 年就写过一篇博客,关于 Next.js 如何完成耐久化缓存
其中有个demo可以很好的说明 next.js 不能完成耐久化缓存,咱们可以在 codesandbox 中体会。
完成办法是每个 page 页面直接引证 components 文件下的导航组件,当点击横向滚动条后边的导航页面,会导致整个页面都改写,然后没有记录滚条的方位。
他处理办法是,需求通过往 Page 页面函数上添加静态办法getLayout
来完成,概况代码可以看这个比方。
import SiteLayout from '../../components/SiteLayout'
import { getLayout } from '../../components/AccountSettingsLayout'
const AccountSettingsBasicInformation = () => <div>{/* ... */}</div>
AccountSettingsBasicInformation.getLayout = getLayout
export default AccountSettingsBasicInformation
比方上面比方中的账户设置—->基本信息
页面代码,是在 Page 页面中绑定 getLayout
静态办法,getLayout
回来页面的公共导航组件。
在 _app.tsx
中调用 getLayout
办法,然后差异各个页面的 layout
布局不同。
import React from 'react'
import App from 'next/app'
class MyApp extends App {
render() {
const { Component, pageProps, router } = this.props
const getLayout = Component.getLayout || (page => page)
return getLayout(<Component {...pageProps}></Component>)
}
}
export default MyApp
假如你也有之前的 Next 项目,也需求完成耐久化缓存,可以参阅这个比方。
app 文件夹下的约好式路由
Next13 新增了 app 文件夹
来完成约好式路由,完美地完成了耐久化缓存,以下是官方 with-turbopack
项目下部分页面结构
./app
├── GlobalNav.tsx
├── layout.tsx
├── page.tsx
├── layouts
│ ├── CategoryNav.tsx
│ ├── [categorySlug]
│ │ ├── SubCategoryNav.tsx
│ │ ├── [subCategorySlug]
│ │ │ └── page.tsx
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── template.tsx
│ ├── layout.tsx
│ ├── page.tsx
│ └── template.tsx
对应的页面效果如下图
咱们看到每个文件下都有 3 个文件 layout.tsx
、page.tsx
、template.tsx
、
-
layout.tsx
该路由下的公共导航,切换路由时,不会改写,咱们可以看箭头处的 Count 组件,并没有改写
-
template.tsx
该路由下的公共部分,切换路由时,会改写
-
page.tsx
该路由的主页面
当咱们点击导航时分,页面上改写部分边框会高亮闪耀,咱们可以很好地了解代码目录结构组织与页面呈现的路由和烘托。
在 app 目录下每个文件夹下,还可以有 loading.tsx
、error.tsx
-
loading.tsx
该路由的主页面在异步烘托中,会显现的 loading 组件的内容;例如咱们可以用它来写骨架屏(Skeleton)
-
error.tsx
该路由的页面烘托出错,会显现该页面,也便是封装了 React 的 ErrorBoundary。
以上除了 page.tsx
其他文件都是可选的,除了这些约好称号的文件外,咱们可以树立任意文件,比方 components.tsx
、 test.tsx
等自定义文件。app 目录可以很好地将页面、组件、测验文件放在一起,办理代码目录,防止开发时大局查找。
路由分组
app 同层级目录下还支撑多个 layout
, 运用 (文件夹)
区别,(文件夹)
不会体现在路由上,仅仅单纯用来做代码分组。
./app
├── (checkout)
│ ├── checkout
│ │ └── page.tsx
│ ├── layout.tsx
│ └── template.tsx
├── (main)
│ ├── layout.tsx
│ ├── page.tsx
│ └── template.tsx
比方官方 playground 中关于电子商务的比方,main
和 checkout
的 layout 是不同的,可以根据完成功用自定义分组代码目录。
React Server Components
在 app 目录下的组件默许都是 React Server Components,那么 React Server Components 有什么优势呢?
这里有几个概念
-
CSR:一切前端打包到前端,通常会引起浏览器加载 JavaScript 过大,然后导致首屏白屏时刻过长
-
SSR:数据在服务端恳求,通过 renderToString
办法将字符串 DOM 结构输出给浏览器,此时浏览器还不能交互,React 不能办理现已存在的 DOM,需求从头履行一遍,这个过程叫“灌水”(Hydrate)。Next12 getServerSideProps
的烘托办法也便是 SSR。
SSR 处理了白屏时刻过长的问题和 SEO 的问题,但也并不是完美的,过多的恳求会导致服务端呼应时刻变长,“灌水”(Hydrate)的过程也会导致客户端代码量的添加。
比方一个传统的博客页面选用 Next12 的办法运用getServerSideProps
的办法烘托,那么就需求等 3 个接口悉数回来才可以看到页面。
export async function getServerSideProps() {
const list = await getBlogList()
const detail = await getBlogDetail()
const comments = await getComments()
return { props: { list,detail,comments } }
}
- React Server Components ( RFC ) 与传统的 SSR 不同,优点是拥有流式 HTML 和挑选性灌水
React Suspense
API 解锁了 React 18 中的两个首要 SSR 功用:
比方上面的博客实例,谈论接口查询速度较慢,就可以运用 Suspense
完成流烘托。
import { lazy } from 'react';
const Comments = lazy(() => import('./Comments.js'));
return (
<Layout>
<NavBar />
<Sidebar />
<RightPane>
<Post />
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
</RightPane>
</Layout>
)
如图所示
- 灰色部分代表 HTML 字符串回来
- loading 状况表示当时部分还在恳求
- 绿色部分代表灌水成功,页面可以交互
所谓的流便是通过 script 动态回来最小 html,而且刺进到正确的方位,页面中假如有多个 Suspense,是没有先后顺序的,React Server Components 是并行的。
以上内容在《New Suspense SSR Architecture in React 18》 中可以找到,而要搭建 react 流烘托的架构相比照较复杂,咱们可以看 gaearon dan 的 demo,而 Next.js 13 只需求在 app 目录下,依照约好的文件称号写,就可以主动完成 React Server Components。
完成流烘托
除了 app 目录下嵌套路由部分 next.js 会帮咱们默许选用 React Server Components,咱们在 page 页面中,也可以完成。
完成办法也很简单,组件外层运用 Suspense
import { SkeletonCard } from '@/ui/SkeletonCard';
import { Suspense } from 'react';
import Description from './description';
export default function Posts() {
return (
<section>
<Suspense
fallback={
<div className="w-full h-40 ">
<SkeletonCard isLoading={true} />
</div>
}
>
<Description />
</Suspense>
</section>
);
}
组件数据恳求运用 use
API,就可以完成流烘托了。
import { use } from 'react';
async function fetchDescription(): Promise<string> {
return fetch('http://www.example.com/api/data').then((res)=>res.text())
}
export default function Description() {
let msg = use(fetchDescription());
return (
<section>
<div>{msg}</div>
</section>
);
}
运用场景
从官方的 playground 中看,在一些恳求较慢的接口,比方电商网站中的价格核算,若要运用服务端烘托,就可以运用 server Component。
服务端组件和客户端组件
Next.js 最大的优势便是咱们只需求一个工程,就可以搞定前端工程和后端工程,哪些是前端代码和哪些是后端代码,Next.js 在打包的时分就会帮咱们主动区别,这需求开发者清楚地了解,自己写的代码哪些是在服务端履行,哪些是在客户端履行。
Next12 区别
咱们知道 Page 函数都是在服务端履行的,包括 getServerSideProps
、getStaticPaths
、getStaticProps
,那么假如需求在客户端履行有以下 2 种办法;
- 在
useEffect
、 onChange
等回调函数中运用,比方下面比方,动态加载了 fuse.js
,完成模糊搜索。
import { useState } from 'react'
const names = ['Tim', 'Joe', 'Bel', 'Lee']
export default function Page() {
const [results, setResults] = useState()
return (
<div>
<input
type="text"
placeholder="Search"
onChange={async (e) => {
const { value } = e.currentTarget
// Dynamically load fuse.js
const Fuse = (await import('fuse.js')).default
const fuse = new Fuse(names)
setResults(fuse.search(value))
}}
/>
<pre>Results: {JSON.stringify(results, null, 2)}</pre>
</div>
)
}
- 假如依靠了外部组件,或许 window 目标,可以运用
next/dynamic
而且设置 ssr
为 false
import dynamic from 'next/dynamic'
const DynamicHeader = dynamic(() => import('../components/header'), {
ssr: false,
})
Next13 区别
在 Next13 中 , 在 app 目录下,如要运用 useState
等状况办理的 hook,那么该组件只在客户端履行,需求在首行加入 'use client'
指令。
'use client';
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
该区别服务端组件和客户端组件,下表列出了常用运用场景
运用场景 |
服务端组件 |
客户端组件 |
fetch 恳求数据。 |
✅ |
[⚠️] |
拜访后端资源(直接) |
✅ |
❌ |
在服务器上保存灵敏信息(拜访令牌、API 密钥等) |
✅ |
❌ |
坚持对服务器的很多依靠/减少客户端 JavaScript |
✅ |
❌ |
添加交互和事情侦听器(onClick() ,onChange() 等) |
❌ |
✅ |
运用状况和生命周期效果(useState() ,useReducer() ,useEffect() , 等) |
❌ |
✅ |
运用仅限浏览器的 API(window) |
❌ |
✅ |
运用依靠于状况、效果或仅浏览器 API 的自定义 hooks |
❌ |
✅ |
运用React 类组件
|
❌ |
✅ |
数据恳求
运用 react 的 use 函数加 fetch API 来完成:静态站点生成(SSG)、服务器端烘托(SSR)和增量静态再生(ISR)
在 Page 页面运用 fetch:
import { use } from 'react';
async function getData() {
const res = await fetch('...');
const name: string = await res.json();
return name;
}
export default function Page() {
const name = use(getData());
return '...';
}
fetch 的缓存策略
fetch(URL, { cache: 'force-cache' });
fetch(URL, { cache: 'no-store' });
fetch(URL, { next: { revalidate: 10 } });
运用这种办法的优点是,当恳求数据的添加,打包后前端 JavaScript 的大小不会添加。
新的 next/image
咱们知道在 Next.js 12 之前,运用 <img>
标签,eslint 会有一个正告,提示咱们有必要运用 next/image
组件, 因为 next/image
帮咱们做了几点优化
- 主动优化图片格局
- 主动缩放图片大小
- 运用
Intersection Observer API
完成懒加载
所以 image 有必要加上 width
和 height
参数
新的 Next/image 运用了浏览器的 lazy-loading 代替了 Intersection Observer API
默许情况下需求 alt 符号,因而减少了客户端 JavaScript 代码,当然这个属性对浏览器要求较高,要求 chrome 77+。
import Image from 'next/image';
import avatar from './lee.png';
function Home() {
return <Image alt="leeerob" src={avatar} placeholder="blur" />;
}
@next/font
加入了一个新的包,可以在构建时直接引证 google 字体和本地字体,完成字体的保管和预加载,这点对英文网站很有用,中文网站一般不加载字体,图标主张运用 svg。
加载谷歌字体
import { Inter } from '@next/font/google';
const inter = Inter();
<html className={inter.className}>
加载本地字体
import localFont from '@next/font/local';
const myFont = localFont({ src: './my-font.woff2' });
<html className={myFont.className}>
next/link
主动加上 <a>
标签。
Next.js 12: 需求<a>
包裹
import Link from 'next/link'
<Link href="/about">
<a>About</a>
</Link>
Next.js 13: <Link>
不需求 <a>
<Link href="/about">
About
</Link>
小结
本文首要结合了 Next13 官网博客 摘取了部分内容,结合笔者对 Next.js 的了解和分析,介绍了其变动、运用办法,以及其改动原因, Next13 这次更新首要与 React server component 深度结合,在”用户体会、可维护性、功能”这几个方面都带来了巨大的提高,本认为 React 的 Server component 还遥不可及,但 Next13 却让咱们触手可及, Next13 也将成为升级 React18 的首选结构,未来前后端并行的开发形式或许可以成为主流,这也将是对前端开发者的一个挑战。
以上便是本文的悉数内容,关于 Next13 你学会了吗?欢迎在谈论区留言讨论,文中若有不正之处,万望奉告。
相关文章
写在前面 好久没更新文章了,各种原因也不提了,今天给我们介绍一个我自己开发的脚本...
0
0
34
面试中发现很多人对rem布局的原理不是很清楚,只停留在会运用的阶段,rem布局的...
0
0
451
本文首要介绍 Android 多渠道打包的一些配置方法和技巧,以及开源打包脚本的...
0
0
39
回顾过去才干展望未来,真正的勇士勇于自我刨析,和面临刨析后鲜血淋漓的自己 -- ...
0
0
33