Preface
被迫向生活妥协,哪有什么鬼的生活与远方,能找到工作就不错了,操蛋的人生。
Contents
不用国内的文档,问题太多了。
创建项目
1 | npx create-next-app@latest |
之后 npm run dev
就可以看到效果。
1 | "scripts": { |
新建项目的一些说明
- app/page.tsx : 类似主页
- app/layout.tsx : 所有页面的根容器,这个页面没有写的话,会在
npm run dev
的时候自动生成 - public : 这里用于存放静态资源的,如,图片,字体等。 在代码中可以直接以
/
前缀访问
一些原则
服务端组件与客户端组件之间的传值
服务端组件与客户端组件之间的值传递需要序列化。也就是函数,日期这样的对象不能直接传给客户端组件。
仅限服务端的代码不要和客户端组件混到一起,这个是很致命的
可以使用 server-only 包给开发者报错。 cnpm i server-only
,然后到仅限服务端的代码中导入即可。
数据获取
虽然客户端组件也可以获取数据,建议是通过服务端组件获取数据,除非特殊原因。服务端组件获取数据更快更方便。
第三方组件
服务端组件是一个新的概念,所以生态系统跟不上。很多组件 use client
没有指令会导致在服务端组件中使用的时候会报错。这个时候需要我们自己在本地封装一下:
1 | 'use client'; |
并不是所有的三方组件都需要封装一下,有一个例外是 provider 组件,因为他们只依赖React state和context,通常他们用在应用的root处。
Context
大部分的React应用依赖 context 在组件之间共享数据,或者直接通过 createContext*,或者通过第三方库 *provider 导入。
从 Next.js 13开始, 客户端组件全面支持 context*, 但是不能直接在服务端组件中创建或者消费。这是因为服务端组件没有 React state,因为他们不能交互,
*context 主要用于渲染完成后渲染树下的交互组件。
1 | 'use client'; |
- 在 root 中创建 context 会导致报错。
- context 的 provider 一般会在 root 附近创建,这样依赖可以提供全局支持。
服务端组件间共享数据
服务端组件不支持React。那么可以通过js自身的一些能力来做数据共享,如单例。
请求结果数据的共享是不必要的耦合。
路由
一般 app 底下的都是服务端组件。
路由约定
- 文件夹用于定义路由
- 叶子文件夹中包含了 page.js 用于定义UI
文件约定
客户端路由包含的文件: - page.js : 定义路由的UI,并且使次路由可公开访问
- route.js : 创建路由的服务端api端点
- layout.js : 为一个 segment 和它的子元素创建共享 UI 。一个 layout 包装了一个页面和他的子集。
- template.js : 和 layout.js 类似, 他会为导航中的每个字元素创建一个新的实例,这意味着state不会保留,每次都是重新创建。除非你需要这个特性,否则直接使用layout。
- loading.js :
- error.js :
- global-error.js :
- not-found.js
当然,也可以添加其他文件,如css,测试用例,组件等等
利用客户端导航的服务端路由
服务端组件和客户端组件不一样。
部分渲染
兄弟路由之间导航的时候,Next.js只渲染路由变动的部分,不会重新渲染整个也看。
高级路由
- 平行路由 : 一次展示多个页面,多用于仪表盘
- 拦截路由 :
修改
可以通过内置的SEO支持,在 app 文件夹下面修改 <head>
元素,如 title,meta
路由之间的导航方法
- Link 组件, 需要href属性
- useRouter 钩子
Link
可以使用usePathname()
来判断链接是否是激活状态。
方式滚动到顶部
1 | <Link href="/#hashid" scroll={false}> |
useRouter
1 | 'use client'; |
无特殊要求可以直接用 link 组件。
一些概念
Server Component Vs Client Component
服务端组件只在服务端渲染,可以在页面初始化的时候提速;客户端组件优先在客户端渲染,但是服务端也可以进行预渲染然后在客户端合成。'use client'
必须定义在第一行,所有import之前,模组里面只要在入口点定义一次就可以了,然后在模组里面导入的其他组件都将被视为客户端组件。
|场景|Server Component| Client Component |
|—-|—-|—-|
| 获取数据 | ✅ | ❎ |
| 访问后端资源 | ✅ | ❎ |
| 敏感数据保存在服务端(访问token,api key等等) | ✅ | ❎ |
| 将大型依赖保存在服务端/减少客户端js | ✅ | ❎ |
| 添加互动与事件监听 例如:onClick,onChange 等 | ❎ | ✅ |
| useState和生命周期effect : useState,useReducer,useEffect等 | ❎ | ✅ |
| 使用仅浏览器支持的api | ❎ | ✅ |
| 使用基于state,effect或者仅支持浏览器api的自定义钩子 | ❎ | ✅ |
| 使用React Class Component | ❎ | ✅ |
组合使用的渲染流程
- 服务端在将渲染结果发送到客户端之前渲染所有的服务端组件
- 包括了客户端组件内嵌的服务端组件
- 遇到客户端组件就跳过
- 在客户端React渲染服务端返回的服务端组件渲染后的结果中的客户端组件和插槽
- 如果客户端组件中嵌入了任何服务端组件,他们的渲染内容会正确的渲染到客户端组件中
Next.js 在初始页面加载期间,会将以上组件渲染结果提前备服务端预渲染成html,以使页面加载更快。
在服务端渲染组件中的子客户端组件中,可以直接插入服务端组件。
鉴于以上流程,在客户端组件中导入服务端组件有一些限制:
不能直接导入服务端组件,建议通过props的方式传入