← 返回文章流

next 框架学习.md

> 时间:2026/07/17/17:31 ## html 生成时机不同产生的不同渲染方式:CSR、SSR、SSG、ISR ``` HTML 什么时候生成? │ ┌────────────┼────────────┐ │ │ │ ▼ ▼ ▼ 浏览器生成 请求时生成 提前生成 CSR SSR SSG │ ▼ 可以重新生成 │ ▼ ISR ``` - CSR(Client Side Rendering,客户端渲染):Vue、React 创建的普通 SPA 默认采用 CSR。服务器返回一个几乎为空的 HTML(通常只有一个 `root` 节点),浏览器下载并执行 JavaScript 后,React/Vue 才开始渲染页面,因此页面是在客户端生成的。 - SSR(Server Side Rendering,服务端渲染):每次请求页面时,服务器都会重新执行渲染逻辑,生成最新的 HTML 返回给浏览器,因此能够保证数据实时,但每次请求都会产生渲染成本。 - SSG:静态站点生成,前端项目在构建时便生成了静态的html文件,该文件中包含了完整的数据,当网站部署后,服务器直接返回该html,渲染开销小,但可能存在过时问题,因为构建时的数据可能会随着时间过时,但一次构建,一直复用 - ISG(Incremental Static Regeneration):ISR 是 SSG 的扩展。页面仍然可以复用预渲染结果,但 Next.js 可以按照时间或主动失效策略,在部署后重新生成对应页面或缓存内容,而不需要重新构建整个网站。 以上四点并不是孤立的,在不同情况下可以选择不同的方式,trade-off ## app router App Router 将应用组织成一棵 Route Tree。客户端导航时,Next.js 可以复用未变化的共享 Layout,只更新发生变化的路由分支。 `Users`页面: ``` RootLayout │ ├── DashboardLayout │ │ │ └── UsersPage │ └── LoginPage ``` `Orders`页面: ``` RootLayout │ ├── DashboardLayout │ │ │ └── OrdersPage │ └── LoginPage ``` 真正改变的只有 Page,其它组件没有改变,如:`RootLayout` ## 路由:目录结构即是路由 在next中,路由无需特殊配置,项目的目录即是路由 ``` app/ ├── layout.tsx └── dashboard/ ├── layout.tsx └── users/ └── page.tsx ``` 访问url `/dashboard/users/` 便对应到 ``` app/ ├── layout.tsx └── dashboard/ ├── layout.tsx └── users/ └── [page.tsx] ``` `page.tsx` 文件是路由节点的入口文件 ## layout:next自动组装嵌套layout 与vue、react框架不同,next会自动组装layout vue和react需开发者手动编写嵌套的layout: ```vue ``` 这是通过开发者编写代码实现的layout,而next无需如此,在目录进行处理后,next会自动组装layout ``` app/ ├── layout.tsx ├── dashboard/ │ ├── layout.tsx │ └── users/ │ └── page.tsx ``` 访问: ``` /dashboard/users ``` next会自动组装layout,得到 ``` RootLayout ↓ DashboardLayout ↓ UsersPage ``` next会根据目录进行递归和组装,得到url完整的layout: - **递归(Recursion)**:对目录进行递归,层层找到url所关联的layout - **组装(Compose)**:将递归的所找到的layout文件全部组装起来 ## root layout和layout 由于app目录结构即是路由,若存在以下架构: ``` app/ ├── layout.tsx ├── dashboard/ │ ├── layout.tsx │ └── users/ │ └── page.tsx ``` 可以发现有两个layout.tsx,在访问 dashboard/users 路由时,会将两个layout进行自动组装(无需手动配置,next自动完成) 其中 Root Layout 有点特殊,必须返回html和body,因为:Next.js 在服务器端生成完整的 HTML Document,并返回给浏览器,但整个next项目中并没有类似于vue或者react需要创建一个index.html,而html需要两个标签组成:html和body标签,考虑到layout的特殊性,next会进行layout tree 构建,因此,html标签和body标签的任务便交给Root Layout了,在Root Layout中配置html标签和body标签 Root Layout 实际上取代了传统 SPA 中的 `index.html` 和 `App.vue`,既负责生成完整的 HTML Document,又作为整个应用的根布局 当然其它layout.tsx无需配置也不能配置html和body标签,因为,一个html文件只能有一个html标签和body标签 ## Template Template 的出现是因为:layout,在页面切换和跳转时,layout会保留状态和数据,例如: - 在root layout中定义了count - 在users页面将count增加到6 - 切换为orders页面时,count的状态不会重置,而是保持为6 但项目中并不是所有的切换都需要保留状态的,如:路由变化状态需重置,此时便需使用 template,template可以看做layout的特殊版: - template 与 Layout 一样可以包裹子内容 - template 当路由变化时会触发卸载和挂载,而layout则保留状态 next构建Route Tree时template所处位置?——layout的下一层级 ``` Layout └── Template └── Children ``` ## Server Component 和 Client Component Server Component 和 client Component 并不是对前端与后端的区分,而是对组件运行环境的区分 ``` Server Component = 后端代码 ❌ Client Component = 前端代码 ❌ ``` 这是错误的,Server Component 和 client Component 是对前端组件进行划分,由于大部分UI不需要浏览器能力,因此默认放服务器更合理,服务器直接返回渲染后的HTML(类似于SSR),而 client Component 则是需要浏览器运行环境的组件,如:点击、键盘与鼠标监听等事件是需要浏览器运行环境的,此时需指定 client Component next 框架默认组件是 server component,其设计理念是: > 大部分UI不需要浏览器能力,因此默认放服务器更合理 与传统前端的区别是,对前端组件进行了细化,传统前端组件都由浏览器渲染和执行 ```js // vue或react function UserList(){ const [users,setUsers] = useState([]) useEffect(()=>{ fetch("/api/users") .then(...) },[]) return ( ... ) } ``` 流程: ``` 浏览器 ↓ 下载 JavaScript [额外的开销] ↓ 执行 React ↓ useEffect ↓ 请求 API [额外的开销] ↓ 获取数据 ↓ 重新渲染 ``` 而next的server component则将无需浏览器环境的组件进行直接渲染,返回渲染后的组件html代码: ``` 浏览器请求 ↓ Next Server ↓ 执行 Users() ↓ 查询数据库 ↓ 生成 React Server Payload ↓ 生成 HTML ↓ 返回浏览器 ``` 与 vue或react框架的对比是:减少api调用开销,服务器直接查询数据并渲染,将渲染后的html返回给前端 ## client component 依赖传递 在前端开发中,组件并不是独立的,在大多时候是嵌套使用的,此时若父组件为 client component,那么父组件所依赖的所有子组件都会是 client component,但server component并不会 > 疑问:为什么client component的依赖会传递? > > 解答:依赖问题,若父组件是client component,那么父组件必然在浏览器环境运行,但父组件所依赖的子组件呢?——也需满足在浏览器环境运行,否则会出问题,如:子组件只能在server运行(如:数据库查询),那么父组件所依赖的子组件无法在浏览器运行,子组件会在浏览器环境崩溃,进而导致父组件崩溃,因此client component的关系是层层递进的,父->子 推荐方式: Server Component 负责数据获取和页面结构,Client Component 负责交互;即父组件为server component,子组件决定是否为client component ``` Server Component (父) | | ↓ Client Component (子) ``` 困惑:没有理解这一节中的技巧,client component可以通过props接受server component ## 技巧:client component 可通过props接受server component client component 与 server component的核心区别在于: - Client Component 的 import 会形成依赖链,父->子,若父为client component,那么子也为client component - Server Component 可以渲染 Client Component,即server component并不会形成依赖链,子组件可在两种类型中做选择 由于 client component的依赖链,下方的例子是错误的: ```react "use client" import ServerComponent from "./ServerComponent" export default function Client(){ return ( ❌ ) } ``` 父组件为 client component,所导入的子组件仍需为 client component 但,props可以避开client component的依赖链,类似于vue的插槽,插槽并不会在意传入的内容是client component还是server component ```react // Client.tsx "use client" export default function Client({ children }){ return ( {children} ) } ``` 述例子中通过 props 传递参数,`children` 可为server component / client component ## hydration 水合 > 服务器输出的 HTML 像干燥的植物,js运行后为它浇水,重获生命 水合是什么?——以SSR进行说明,SSR用户每次访问网站时

作者:Tilex作者主页
在原博客阅读全文 (新标签页打开)

以上内容来自博客订阅源,版权归原作者。关注作者后可以在 关注列表 第一时间查看作者文章。

一起聊聊 0

尊重不同观点

还没有评论。欢迎分享第一个想法。

RSS SUBSCRIPTIONS

选择 RSS 订阅

把博客汇的文章添加到你常用的阅读器。

关注文章 RSS 订阅本订阅需要登录后使用