Next.js 使用总结


以下内容仅针对 Next.js 13.4+ app router, 不会涉及到低版本或者 Next.js Pages 的部分 (整理中)

Usesearchparams

Next.js 中的 usesearchparams 不是完整的,useSearchParams is a Client Component hook that lets you read the current URL's query string. useSearchParams 是一个客户端组件挂钩,可用于读取当前 URL 的查询字符串。

useSearchParams returns a read-only version of the URLSearchParams interface. useSearchParams 返回 URLSearchParams 接口的只读版本。

Server Components vs server actions

server action just suitable for form tag ???

Next.js integrates with React Actions to provide a built-in solution for server mutations.

Server Actions can be defined in two places: 服务器操作可以在两个位置定义:

Inside the component that uses it (Server Components only). 在使用它的组件内部(仅限服务器组件)。 In a separate file (Client and Server Components), for reusability. You can define multiple Server Actions in a single file. 在单独的文件(客户端和服务器组件)中,以实现可重用性。您可以在单个文件中定义多个服务器操作。

https://nextjs.org/docs/app/api-reference/functions/server-actions https://blog.greenroots.info/understanding-nextjs-server-actions-with-examples

PPR(Partial Prerendering )

Partial Prerendering is an experimental feature that allows static portions of a route to be prerendered and served from the cache with dynamic holes streamed in, all in a single HTTP request.

部分预渲染是一项实验性功能,它允许在单个 HTTP 请求中预渲染路由的静态部分,并从缓存中提供动态空洞。

Project organization

About Next.js i18n

About Cache

由于 Next.js 的路由缓存,revalidate 即使成功,有时也会看到过去的数据,revalidate 也不是及时会更新,需要等到新的数据成功获取,类似于 service worker 或者 swr

The first time a fetch request with revalidate is called, the data will be fetched from the external data source and stored in the Data Cache. 第一次调用 fetch revalidate 请求时,将从外部数据源获取数据并存储在数据缓存中。

Any requests that are called within the specified timeframe (e.g. 60-seconds) will return the cached data. 在指定时间范围内(例如 60 秒)调用的任何请求都将返回缓存的数据。

After the timeframe, the next request will still return the cached (now stale) data. 在时间范围之后,下一个请求仍将返回缓存的(现已过时)数据。

Next.js will trigger a revalidation of the data in the background.

Next.js 将在后台触发对数据的重新验证。

Once the data is fetched successfully, Next.js will update the Data Cache with the fresh data. 成功获取数据后,Next.js 将使用新数据更新数据缓存。

If the background revalidation fails, the previous data will be kept unaltered. 如果后台重新验证失败,则以前的数据将保持不变。

This is similar to stale-while-revalidate behavior. 这类似于 stale-while-revalidate 行为。

// revalidate tag fetch
{
next: {
revalidatetag: 'xxx';
}
}
// revalidate tag fetch
{
next: {
revalidatetag: 'xxx';
}
}

Route Handler

route.(js, ts)

Route

NOTE: (_test) route will be exclude

// layout.tsx
export default function Layout(props: {
children: React.ReactNode;
analytics: React.ReactNode;
team: React.ReactNode;
}) {
return (
<>
{props.children}
{props.team}
{props.analytics}
</>
);
}
// layout.tsx
export default function Layout(props: {
children: React.ReactNode;
analytics: React.ReactNode;
team: React.ReactNode;
}) {
return (
<>
{props.children}
{props.team}
{props.analytics}
</>
);
}

Slots are not route segments and do not affect the URL structure. The file path /@team/members would be accessible at /members.

关于 use client

你也可以用 `import 'client-only'

https://stackoverflow.com/questions/74992326/does-use-client-in-next-js-13-root-layout-make-whole-routes-client-component https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#supported-pattern-passing-server-components-to-client-components-as-props layout.js 里面是可以使用 use client, 不会导致子组件全部变成 client

RSC(React Server Component)

注意:RSC 不是 ssr 的升级 (他们是两种不同的概念)

video: https://www.youtube.com/watch?v=g5BGoLyGjY0

https://nextjs.org/docs/app/building-your-application/rendering/server-components There are a couple of benefits to doing the rendering work on the server, including:

  1. Data Fetching: Server Components allow you to move data fetching to the server, closer to your data source. This can improve performance by reducing time it takes to fetch data needed for rendering, and the amount of requests the client needs to make.

  2. Security

  3. Caching:

  4. Bundle Sizes

React renders Server Components into a special data format(可序列的数据化的数据,用于 server=> 向 client 的数据传递) called the React Server Component Payload (RSC Payload), which includes references to Client Components(占位符). (rsc payload 和 client component 进行 hydration(水合), 渲染 html, 使其具备交互能力) The React Server Components Payload is used to reconcile the Client and Server Component trees, and update the DOM.(维护 dom tree)

Since Client Components are rendered after Server Components, you cannot import a Server Component into a Client Component module (since it would require a new request back to the server). Instead, you can pass a Server Component as props to a Client Component. See the unsupported pattern and supported pattern sections below. (之所以不能嵌入就是因为最小边界时文件不是组件), props 可以保证完全区分组件类型,使用占位符代替,注意这里的数据必须时可序列化的,对象/函数是不能作为 props 传递的

// clientcomponent.tsx
'use client';

import ServerComponent from './ServerComponent';

export default function ClientComponent({
server
}: {
server: React.ReactElement;
}) {
return (
<div>
<div>ClientComponent</div>
<div>server content is : {server}</div>
{/* <div>{children}</div> */}
</div>
);
}

// servercomponent.tsx
('use server');

export default async function ServerComponent() {
// const a = { a: 1 }; // wrong
// const aa = [{b: 2}] // wrong
const a = ['hi', 2]; // binggo
console.log('Hello from Server Component');
return <>Hello from Server Component {a}</>;
}

// page.tsx
<ClientComponent server={<ServerComponent />} />;
// 这种传 props 的用法不多,更多的是 client component nesed to server component

// 为了减少客户端的 JS bundle size, 尽量保持 client component move to client, 但是 那种 props 传递的 server component 的用法对此没有影响,因为客户端渲染的时候会跳过 client, 要避免的主要是直接在父级直接使用 client, 导致嵌入的组件全部变成了 client, 尽量将 client 抽离出去
// clientcomponent.tsx
'use client';

import ServerComponent from './ServerComponent';

export default function ClientComponent({
server
}: {
server: React.ReactElement;
}) {
return (
<div>
<div>ClientComponent</div>
<div>server content is : {server}</div>
{/* <div>{children}</div> */}
</div>
);
}

// servercomponent.tsx
('use server');

export default async function ServerComponent() {
// const a = { a: 1 }; // wrong
// const aa = [{b: 2}] // wrong
const a = ['hi', 2]; // binggo
console.log('Hello from Server Component');
return <>Hello from Server Component {a}</>;
}

// page.tsx
<ClientComponent server={<ServerComponent />} />;
// 这种传 props 的用法不多,更多的是 client component nesed to server component

// 为了减少客户端的 JS bundle size, 尽量保持 client component move to client, 但是 那种 props 传递的 server component 的用法对此没有影响,因为客户端渲染的时候会跳过 client, 要避免的主要是直接在父级直接使用 client, 导致嵌入的组件全部变成了 client, 尽量将 client 抽离出去

自从 React18 的文档更新以后,引起了不小的讨论,react 不再一味的像以前推荐 CRA, 而是建议使用基于 React 的框架进行学习 React, 而且这一推荐放在了很重要的开头位置 (NextJs 和 React 的合作很密切)

有人认为新手学习 React 就使用框架会不会太重,也有人觉得新手就应该使用框架,因为 React 只能算一个 Ui 库,不足以真正满足开发需求,如果不使用框架,什么都要自己进行配置,打不到最佳实践

NextJs 13 让 RSC 有重新出现在人们眼前, React

已经一年没有发版,React 实在进行底层库的转变 (越来越像一个库)

Next.js Cache

next 缓存总是会导致一些奇怪的 bug, 本地开发需要 rm .next, vercel 需要重新部署

比如手动加上 postcss.config.js 后,需要清空缓存,因为 tailwindcss 缺少这个文件是不能正常工作的,之前的 cache 是不会自动更新这部分的,需要清空缓存,从来没了解过缓存是根据什么机制更新的,从之前的电脑有问题第一想到的是重启,现在我第一时间选择 rm .next, 然后清空浏览器缓存

Tailwind

Tailwind 在 NextJs 里面似乎很受支持(:rocket:),

直接在 CNA 里面内置了选项支持

ps: 今天才知道 tailwindcss 原来还有个 tailwindcss@insider 的 package(text-balance 只有这里能用,我说那个 pr 明明合进仓库了,为什么用不了,翻了 issue 才知道)

React

react 当前的生态有点类似与 archlinux, neovim, 很容易产生 break change, 灵活的同时,也带来了一定的成本

shadcn-ui

NextUI

Assert File

mp3.config.js
webpack: (
config,
{ buildId, dev, isServer, defaultLoaders, nextRuntime, webpack },
) => {
config.module.rules.push({
test: /\.mp3$/,
type: 'asset/resource',
generator: {
filename: 'static/chunks/[path][name].[hash][ext]',
},
});
// Important: return the modified config
return config;
},
mp3.config.js
webpack: (
config,
{ buildId, dev, isServer, defaultLoaders, nextRuntime, webpack },
) => {
config.module.rules.push({
test: /\.mp3$/,
type: 'asset/resource',
generator: {
filename: 'static/chunks/[path][name].[hash][ext]',
},
});
// Important: return the modified config
return config;
},