2024-11-03

为什么要学习nextjs?

学习了vue,我也没有专门学习额外的框架啊,不照样可以写项目吗?也许后来有了若依框架,JNPF框架,PigX框架,也只是vue的知识,不需要额外学习的。(2025-10-28,前面举的例子都是完整的项目框架,不是nextjs这种类型的框架,nextjs可以算是一个前端框架)

为什么呢?因为react做项目涉及到很多方面的问题,比如说路由怎么组织、数据怎么请求、数据返回之后组件怎么重新渲染、如何将渲染限定在某个具体的组件上面等等很多问题。那么程序员水平有高有低,解决这些问题就会花很长时间,合作起来也很麻烦,真正的业务实现就会被压缩时间。此时就出现了很多解决方案,那么nextjs就是其中的佼佼者。

甚至react官网都推荐使用Nextjs或者remix框架了。

image-20241103113402183

官网说的很清楚了,react只是一个库,如果要用到路由和数据请求来写一个完整的app,建议使用全栈react框架,比如说nextjs或者remix。

那么nextjs到底有哪些不同呢?

学习了30集之后,我的一个直观感受就是react的东西在哪里?react-dom在哪里?特别是useEffect在哪里?不是说获取数据的代码要写在这里面吗?

下面是一个视频,解释了nextjs和reactjs的不同,说的很好,对于我深刻理解nextjs有帮助。https://www.youtube.com/watch?v=r8nXMA_pf0w

image-20241103155350497

react is the base of nextjs.

image-20241103155952424

react@18只能支持实验性的SSR,而Nextjs已经完全支持SSR了。

但是SSR也造成了一些问题,比如说在server components上不能定义onClick、onChange等事件。nextjs不是要消除hooks,在特定的情况下我们还是想使用hooks。

image-20241103160700820

image-20241103160728978

为什么需要SSR呢?

client side意味着在浏览器端执行代码,服务端将html、css、js文件发送到client端,浏览器端执行js代码,渲染页面。server side意味着在服务器上执行代码,pre-render the content and send the pre-rendered html file to the client side。但并不意味着完全不发送js代码,但是js代码量 much less than before. 那么浏览器就避免了下载和执行大量js代码,从而增加了渲染速度。

下一个问题:我怎么知道什么时候在client side渲染好,什么时候在server side渲染好呢?

nextjs made a nice chart to show us where to put our code。地址:https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns

image-20241103162429488

但是这位视频博主还是强调,即使是推荐使用client components 的场景,还是有办法使用server components的,主要还是server components渲染确实快。

比如说nextjs官网或者视频博主的网站jsmastery,里面大部分都是静态页面,但是有登录窗口,是不是意味着整个页面都要做成client side components呢?不需要,只需要将Form页面做成client side components 即可,其余的部分做成SSR。

这里带出了一个重要经验:you can choose where to render Even the tiniest element ,说明组件的拆分可以做的非常细。

separate the client and server components.think what has to go on the client versus what can go on the server.

SSR有什么好处呢?

1、Faster initial page load.

2、reduced client side load.

3、better SEO.

4、improved user experience.

5、resource proximity.

SSR是nextjs的一个优点,优点还有file routing system,error state management等等。

重要问题

2025-10-28

其实学习了nextjs之后,我是很有疑问的,因为我在react中学习的很多知识点,在nextjs中好像都没有用到,比如说useMemouseCallbakcuseTransitionuseDeferredValueuseReducer等等,还有最经典的useEffect,这个最起码我觉得要用上,但是学习过程中基本上没有用到。

为什么不需要呢?

其实你观察得非常准确 —— 在 Next.js(尤其是 v13+ 的 App Router 架构) 中, 你确实会发现: 👉 很多地方根本不需要手动用 useMemouseCallback 来优化渲染性能。

这并不是因为 Next.js 不会发生 rerender,而是因为 Next.js 把大部分渲染优化提前到了“服务器端” 我们来分层分析一下为什么。👇


🧩 一、React 自身 rerender 的痛点

在纯 React(前端渲染)项目中:

  • 所有状态、组件、数据请求都在 浏览器端运行
  • 页面渲染逻辑全靠客户端 React 控制;
  • 因此频繁的 setStateuseEffect、函数重建、props 传递都会导致 rerender。

你就需要用:

  • React.memo 避免子组件重复渲染;
  • useCallback 缓存函数;
  • useMemo 缓存复杂计算。

⚙️ 二、Next.js 的重大不同点:默认是服务端渲染(Server Components)

Next.js 13 (App Router) 开始,引入了 React 官方的 Server Components 模式 这彻底改变了渲染逻辑 👇

对比传统 ReactNext.js App Router
组件执行位置浏览器端默认在服务器端
状态管理前端状态服务端计算后传结果
网络请求浏览器 fetch服务器直接 fetch(更快)
Rerender 范围前端全量渲染仅 Client Components rerender
优化需求必须用 useMemo/useCallback大部分情况下不需要

🧠 三、深入理解:Server Components 避免了很多“rerender 场景”

举个例子👇

这里的 PageServer Component

  • 它只在服务端执行一次;
  • React 直接把渲染好的 HTML 发给浏览器;
  • 浏览器拿到后只负责展示;
  • 不存在 “state 改变 → rerender” 这个过程。

💡 所以你根本不需要 useMemouseCallback —— 组件根本不会在客户端重新执行。


🧭 四、那 Next.js 里什么时候会重新渲染?

只有这两种情况:

  1. 使用 “Client Component” 时

    🔸 这个组件才是传统的 React 客户端逻辑。 在这种情况下,useMemouseCallback 才有意义。

  2. 当 props 变化时

    • Next.js 的 Server Components 会智能 diff;
    • 只更新需要重新渲染的部分;
    • 所以 rerender 的范围非常小,性能损耗远小于纯 React SPA。

🧠 五、Next.js 的其他隐形优化手段

Next.js 在底层做了很多性能优化,让你不必手写优化

优化点说明
🔹 Server Components避免前端 rerender,直接在服务器端计算
🔹 Streaming + Partial Rendering页面分块流式渲染,减少阻塞
🔹 缓存 (Route Cache / Data Cache)自动缓存数据请求和组件树
🔹 React Suspense + Lazy Loading自动分块渲染组件,减少初始负担
🔹 Selective Hydration只激活需要交互的组件部分
🔹 静态优化 (Static Rendering)无需请求的页面直接预生成 HTML

👉 因此,在 Next.js 里你几乎感觉不到 “性能调优的负担”。


🧩 六、简单理解一句话:

在传统 React 里,组件是渲染的最小单位 在 Next.js(App Router)里,Server Component 树是渲染的最小单位

也就是说,Next.js 在“更高一层”就把 rerender 控制住了。 你写的组件大多只渲染一次,因此根本不需要频繁用 useMemo/useCallback


✅ 七、总结对比表

特性纯 React SPANext.js (App Router)
渲染位置浏览器服务端(默认)
rerender 频率高频低频
性能瓶颈React diff + 组件重建网络/SSR 流式传输
优化手段useMemo / useCallback / memo默认启用缓存 + Streaming
开发体验手动优化自动优化

💬 简短总结一句话:

你在 Next.js 里很少用 useMemouseCallback 并不是它们没用了,而是 Next.js 通过 Server Components + Cache + Streaming,把大部分 rerender 问题在“框架层”就解决掉了

react和nextjs之间到底有哪些区别呢?

非常好的问题 👍,这个是很多人从 React 转向 Next.js 时的核心困惑。 下面我会用清晰、分层的方式帮你搞懂:


🧩 一、React 与 Next.js 的关系

可以简单地理解为:

Next.js 是一个基于 React 的框架(Framework),不是 React 的替代品。

  • React 是一个前端 UI 库,负责「组件化 UI」和「状态管理」。

  • Next.js 是一个全栈框架,在 React 的基础上增加了:

    • 路由系统(Routing)
    • 服务端渲染(SSR)
    • 静态生成(SSG)
    • API 路由(Serverless Functions)
    • 文件系统路由(File-based Routing)
    • 构建优化、图片优化、字体优化 等功能。

🧱 二、两者在职责上的区别

功能ReactNext.js
UI 组件✅ 负责✅ 继承 React 能力
路由❌ 需要 React Router 等✅ 内置文件路由(app/pages 文件夹)
数据获取❌ 前端 useEffect / SWR✅ SSR / SSG / ISR / API routes
服务端渲染❌ 自己实现很复杂✅ 内置支持(getServerSideProps / generateStaticParams
静态导出⚙️ 需要配置✅ 一行命令即可(next build && next export
打包优化❌ webpack 需手动配置✅ 内置 webpack + SWC 优化
全栈能力❌ 前端框架✅ 支持后端逻辑(API routes)

🧠 三、Next.js 里「可以不使用」React 的哪些东西

Next.js 虽然建立在 React 之上,但帮你「封装」或「简化」了 React 中很多常见的手动工作。 以下是你在 Next.js 里可以不再直接使用或很少使用的部分 React 内容:

React 原生功能在 Next.js 中是否还需要说明
React Router(react-router-dom)❌ 不需要Next.js 自带文件系统路由。
手动配置 Webpack / Babel❌ 不需要Next.js 内置 SWC 打包器。
手动设置懒加载(React.lazy✅/简化Next.js 提供 next/dynamic 更方便。
useEffect 里 fetch 数据✅/部分Next.js 可以用 getServerSidePropsgenerateMetadatafetch() 在服务端拉数据。
React.StrictMode 配置❌ 内置在开发模式不需要再显式配置。
ReactDOM.render()❌ 不再使用Next.js 自己挂载 React 应用。
客户端状态管理(useState、useReducer)✅ 仍可使用UI 内部逻辑依然是 React。
React Context✅ 可用但可以结合 Next.js layout 实现全局状态。

⚙️ 四、Next.js 新的 “App Router” 模式(React Server Components)

Next.js 13+ 引入了 App Routerapp/ 目录),这对 React 使用方式产生了很大变化:

特性React 传统模式Next.js App Router 模式
组件类型全部是 Client Components分为 Server Components + Client Components
数据获取useEffect / fetch in client直接 async function Component() 中使用 await fetch()
状态管理useState/useReducer仅 Client 组件需要状态
性能优化手动拆分自动实现 SSR + Streaming 渲染
SEO需要额外配置天然支持 SSR SEO 优化

👉 换句话说: Next.js App Router 模式 中,React 的很多客户端逻辑(useEffect, useState, context 等)可以只在 “client components” 中使用 服务端组件部分完全不需要写这些。


🧭 五、总结一句话理解

框架定位你需要做的事情
React专注 UI 构建你要自己解决路由、数据、打包、SEO
Next.js全栈 React 框架帮你搞定 SSR、路由、优化、API 层,只专注写组件就行

能够具体说明一下react和nextjs在使用上的区别吗?

非常好 👍,下面是我为你整理的——

🧭 Next.js vs React 功能对照表

「哪些 React 功能在 Next.js 中容易误用、应当改用 Next.js 原生方案」


🧩 一、路由与页面组织

常见 React 做法✅ Next.js 正确做法说明
使用 react-router-dom 配置 <Routes><Route>使用 文件系统路由app/pages/ 目录结构自动对应路径Next.js 自动生成路由,不需要手动配置 Router。
使用 <Link to="/about">使用 next/link<Link href="/about">内置优化的预加载、无刷新跳转。
使用 useNavigate()使用 useRouter()(来自 next/navigation)的 .push().replace()用于编程式导航。

⚙️ 二、数据获取(Data Fetching)

React 做法✅ Next.js 推荐方式说明
在组件里 useEffect(() => fetch(...))使用 Server Component + async/await(App Router 模式)数据在服务端渲染阶段就获取,不闪烁、不依赖 useEffect。
在客户端 fetch 数据getServerSideProps() / generateStaticParams() / getStaticProps() 中获取旧版 pages/ 模式下使用这些生命周期函数。
使用 React Query / SWR✅ 可以继续使用(仅 Client Component)用于动态或交互式数据,Next.js 不限制。

🧠 三、组件与渲染方式

React 功能✅ Next.js 用法说明
仅用客户端组件分为 Server Component(默认) 与 Client Component(含 'use client'Server Components 默认无 JS 开销,性能更优。
手动懒加载:React.lazy() + Suspense使用 next/dynamic()支持 SSR,自动处理加载状态。
使用 ReactDOM.render()❌ 不需要Next.js 内部自动挂载 React 应用。

🧰 四、静态资源与优化

React 方式✅ Next.js 替代方案说明
<img src="..." /><Image src="..." width height />next/image自动图片优化、懒加载、响应式。
手动引入字体(CSS / link)使用 next/font自动优化字体加载、无 FOUT。
手动配置 Webpack/Babel❌ 不需要Next.js 内置 SWC(Rust 编译器)。

🌐 五、SEO 与 Head 管理

React 做法✅ Next.js 方式说明
使用 react-helmet 或手动操作 <head>使用 next/head 或 App Router 的 metadata 导出自动处理 SSR SEO 元信息。
手动配置 meta 标签layout.jspage.js 中导出 metadata 对象类型安全 + SEO 自动化。

🧩 六、后端逻辑(React 不具备)

React 做法✅ Next.js 做法说明
需要单独搭建 Express / Node API使用 app/api/route.tspages/api/*.tsNext.js 自带 Serverless API routes。
手动管理 CORS / Proxy内置 API Route 运行在同域,无需跨域适合小型全栈项目。

🧮 七、状态与交互

React 功能✅ Next.js 用法说明
全局状态用 Context / Redux✅ 可以继续使用(仅在 Client Components)Server Components 不支持 React 状态 hooks。
在 useEffect 中依赖 URL 参数直接使用 useSearchParams()next/navigation取代手动解析 URL 查询参数。

🧱 八、构建与部署

React(CRA)✅ Next.js
npm run build 生成静态前端包next build 自动执行 SSR/SSG 打包
需要额外配置 SSR 服务器Next.js 内置 SSR,支持 Vercel、Node、Docker
需要配置环境变量文件Next.js 自动读取 .env.local.env.production

🧭 总结思维导图(文字版)

 

1-Introduction

image-20250908094152980

image-20240829202112871

react is responsible only for the view layer of an application.

image-20240829202238168

image-20240829202605776

image-20240829203541793

2- Hello World

首先安装npx,npm i -g npx,然后运行命令:npx create-next-app@lastest,按照下面的选项创建项目:

注意一下:create-next-app@lastest应该不可用了,但是使用create-next-app可以正常使用。

image-20240829204515160

项目被创建好了:

image-20240829204725726

命令行进入项目地址,使用npm run dev启动项目:

image-20240829204800420

更改src/app/page.tsx里面的内容,写上Hello,world!。

image-20240829205204709

3- Project Structure

next-env.d.ts:typescript声明文件

.eslintrc.json:配置eslint

next.config.mjs:配置nextjs

package-lock.json:包锁文件

package.json:依赖包和脚本

postcss.config.mjs:主要还是配置tailwind相关的

tailwind.config.ts:配置tailwind

tsconfig.json:配置typescript

.next文件夹:当我们运行dev或者build命令时,会生成里面的代码,会创建一个服务器,启动项目。这个文件夹在.gitignore里面是被忽略的,所以在提交git的时候不会跟踪上传,估计和vite的功能差不多。

public文件夹:里面存放着所有静态资源文件

src文件夹:最重要的文件夹,里面编写组件。app文件夹是app路由所在的文件夹,favicon.ico文件是配置到浏览器tab上的,globals.css是供app使用的全局样式,layout.tsx是可以在不同pages里面共享的UI组件,page.tsx是访问localhost:3000时展示的UI组件。

下面简单讲一下npm run dev之后,nextjs做了什么:

当运行了npm run dev之后,实际执行的命令是next dev,命令会传递到app/layout.tsx,RootLayout组件被渲染。当我们访问localhost:3000的时候,RootLayout里面的children参数会指向app/page.tsx里面定义的组件,那么里面的Home组件会被渲染。

4- Befor we start

这一节主要介绍了server components的概念。

image-20240829212152115

image-20250908095753829

trade-off:权衡;(在需要而又相互对立的两者间的)协调。

上面讲解了server components的一些概念,nextjs默认将所有组件都当成server component,这种组件可以执行服务端任务,比如说读取文件,从数据库中获取数据等。权衡就是这种组件不能使用react hooks或者处理用户交互。

image-20250908100226006

上面讲解了client component,如果想在nextjs中,创建一个client component,就需要在component file上面加上"use client"命令,client component不能像服务端组件那样读取文件,但是可以使用react hooks和处理用户交互。

image-20250908100504683

image-20240829212246469

image-20240829212407403

5- Routing

image-20250908101331203

运行命令:npx create-next-app@latest routing-demo,创建新项目,删除app文件夹,从零开始学习route。

上面的图说了,nextjs有一个基于文件系统的路由机制,是不是意味着每一个文件夹就对应着一个路由地址呢?不是的,在介绍nextjs的时候说过,nextjs is a framework where we need to follow certain conventions。这里的conventions就是惯例、约定的意思,说明仅仅是文件夹,不表示一个路由,还需要配置一些东西。下面是路由规则:

image-20250908101530857

场景1:在访问localhost:3000的时候,显示home page 这些字。

image-20240829213509044

这里用到了第一和第二条规则,每个路由都必须放在app文件夹里面,每一个对应路由的文件,都应该命名为page.js或者page.tsx。所以在routing-demo项目中,在src下新建app文件夹,里面新建page.tsx文件,编写一个最简单的组件:

运行npm run dev

image-20240829214202818

注意:此时运行其实是运行不起来的,因为上面的运行流程我们知道,运行命令之后,首先会到layout.tsx里面执行渲染,但是我们连文件都没有,怎么渲染,正当我不知所措的时候,疑惑老师为什么没有讲的时候,nextjs为我们创建了layout.tsx文件,可以正常渲染了。这一点后面会重点讲解。

但是2025-09-08,nextjs 15.2.2好像又不会为我们创建这个layout.tsx文件了,还是要自己创建才能正常渲染。

 

image-20240829214356200

注意:app文件夹里面的page.tsx文件,会映射到域名的root路由,所以访问localhost:3000,其实访问的是app/page.tsx里面的内容。

page.tsx file inside the app folder automatically maps to your site's root URL.

场景2:创建两个额外的路由,about和profile路由,分别指向about page和profile page。

image-20240829214625893

步骤如下:

1、在app文件夹下创建about和profile文件夹,注意文件夹名要全部小写

2、里面分别创建page.tsx文件

3、default export 组件,编写组件

访问localhost:3000/aboutlocalhost:3000/profile

image-20240829215256814

image-20240829215308761

由此可以得出结论:routes are associated with a file based on the containing sub-folders name within the app folder.路由通过app文件夹里面的子文件夹名,来与文件关联。

下面这个动画做的太好了,很好的展示了当我们访问链接时,具体的是访问哪一个文件。

page.tsx in the app folder directly maps to the root route and each folder in the app folder directly maps to a segment in your URL.

当我们访问没有定义的路由地址,会发生什么呢?

image-20240829220109693

nextjs会自动跳转到404界面,不需要我们进行处理,非常方便了。

6- Nested Routes

上一节我们学习了创建简单的路由,在app文件夹里面的page.tsx对应的就是root route,app文件夹里面的子文件夹里面的page.tsx对应的就是 /路由名 这样的路由。下面我们来学习嵌套路由,由一个场景开始。

 

场景3:访问localhost:3000/bloglocalhost:3000/blog/firstlocalhost:3000/blog/second,此时的路由应该怎么编写?

这种场景让我想到了在vue里面喜欢使用v-if、v-show来做,只需要导航到 /blog 页面,然后里面的first、second都可以使用v-if来判断渲染,避免使用太多的路由地址。

但是这里的blog说不定就是一个菜单模块,里面有很多具体的菜单,这时候还使用v-if吗?肯定是不行的。

这里同时给我提出了一个问题:如果blog是一个模块名称,那么打开这个模块的时候,我想默认导航到第一个菜单页面first,该怎么做呢?学习了下面的内容之后,一定要回来回答这个问题。

image-20240830074912880

首先在app里面创建blog文件夹,创建page.tsx文件,编写组件:

访问:

image-20240830075340424

但是localhost:3000/blog/first这样的路由该怎么编写呢?nextjs规定可以直接在blog文件夹里面,创建first文件夹和second文件夹,然后在里面创建page.tsx文件,编写组件。

看一下效果:

image-20240830075900288

image-20240830075910903

 

By creating a nested folder structrue, files will automatically be routed in the same way within the URL.

7- Dynamic Routes

上面学习了嵌套路由,但是上面的嵌套路由都是定义的静态的路由,有时候我们从后端拿到了数据,需要渲染动态的数据,这时候的路由地址就有可能是动态的,那么该怎么做呢?

这里引出了一个问题,我在vue里面使用过动态路由吗?怎么我没有印象呢?

其实vue里面是有动态路由的,比如说下面的代码我就很熟悉:

但是后来大量使用若依框架之后,它里面使用vuex、pinia、组织页面的方式也不同了,这种传参方式就很少使用了。所以后来就渐渐忘记了。

但是这种传参方式在小程序中用的很多,这我是记得很清楚的。

 

那么这种动态路由,具体在nextjs中什么场合使用,还是要做了项目之后才会明白,这里不需要担心,学会就行了。

场景4:访问localhost:3000/products会展示products列表,我们点击某一项之后,会带上这个product的id来查看详情,这里的id会携带在url上,所以怎么处理动态路由呢?

image-20240830080536236

首先在app里面创建products文件夹,创建page.tsx,编写组件。

看一下效果:

image-20240830081623104

 

within a pair of square brackets,let's specify productId.Because nextjs treats square brackets in a folder name as a dynamic segment enabling us to create dynamic routes.

在products文件夹里面创建一个文件夹,文件夹名为[productId],在里面创建page.tsx文件,创建组件。

动态访问一下,看效果,注意看url:

可以看到,对动态id的处理成功了,没有跳转到404。但是这个动态id我要接收到才行,怎么接收呢?Every page in the app router receives route parameters as a prop, we can destructure it as params.The type of params is a promise that resolves to an object containing the dynamic segments as key-value pairs.In this case, that is productId, the name of our folder.

这里定义的[productId],就是路由参数的属性名。

上面的代码有错误,因为params是Promise对象,所以不能直接在{}里面使用,这里会红色波浪线报错:

image-20250908120955996

那么怎么改呢?the nice thing about server components is that we can use async await to resolve the promise, and access the dynamic segment.

所以我们可以使用async...await来access productId.

看一下效果:

总结一下:在这一节我们学习了动态路由,使用中括号square brackets来包裹路由参数,然后在这个动态路由里面使用params来接收参数,params是一个Promise对象,所以我们使用了async...await来接收具体的参数。

需要注意的是:这里并没有使用点击来进行跳转,而是直接在url栏里面更改路由地址来跳转,后面要想一想,这里如果要加上点击跳转功能,该怎么做呢?是不是直接加一个click事件就行了呢?

8- Nested Dynamic Routes

这一节是学习嵌套的动态路由,看了案例需求之后,我想是不是可以直接在[productId]文件夹里面,先创建一个reviews文件夹,然后创建一个[reviewId]的文件夹就行了?请看下去。

场景5:如果我在productId为1的产品详情里面,想查看它的第一个comment详情,那么url就是这样的localhost:3000/products/1/reviews/1,这里的reviews是固定的,后面的1是动态的,那么这种嵌套的路由该怎么编写呢?

image-20240830095004921

解决方法,上节课已经讲了,就是在[productId]文件夹里面创建reviews文件夹,这个文件夹里面可以创建page.tsx,用来当做/products/1/reviews这样的路由页面,但是如果没有这个页面,那么page.tsx可以不创建(其实这样就会有bug,当用户访问/product/1/reviews时,就会出现404,但是这里学习的时候不用管),而是直接创建[reviewId]文件夹,里面创建page.tsx文件,编写组件。

看一下效果:

那么回答一下这一小节开始时我提出的问题,我的答案是对的。

这里有一点需要注意:

如果是底层的动态路由页面,那么它的params就可以接收到之前的参数,不是只能接收自己定义的参数。

下面是路由变化的动图:

课后练习题:

为每一种product创建一个reviewList页面,怎么创建?

 

直接在reviews文件夹里面创建一个page.tsx文件,然后编写如下代码:

 

9- Catch all Segments(重点)

catch all segments,这里的segments老师经常是这样说的:path segments,也就是路径片段。翻译过来就是捕获所有的路径片段,还是很模糊,这个意思就是捕获浏览器url上的所有路径片段。

这种场景应该怎么想象?按照老师的说法应该是一个文档的网站。比如说有5个 feature ,然后每一个feature下面有5个 concept ,这样就意味着5个feature文件夹,每个文件夹里面有5个子文件夹,那么就是25个文件夹。那如果是20 * 20呢?是不是400个文件夹,显然这里可以优化。

这里可以优化的前提是什么呢?在于feature和concept是可以从后端返回的,而且concept的页面内容格式是高度类似的。比如说featureList就显示在/doc这个页面里面,然后conceptList就显示在具体的feature页面里面。当然也可以在/doc页面甚至固定一个树形菜单,都是可以的。

总之,学习这一小节,先不要管左边的树形结构,而是右边的具体内容,是不是需要创建很多个文件夹,这才是重点。

 

场景6:想象我们要创建一个网站,这个网站包含多个feature,每一个feature有多个concept要解释,假设我们的sidenav样式是这样的,我们的目标是每一个concept对应一个路由地址,就像这样:localhost:3000/docs/feature1/concept1,点击每一个concept就在右侧展示详情。

那么我根据上面学习的内容,可以创建一个[featureId]文件夹,在里面创建[conceptId]文件夹,就可以接受到featureIdconceptId参数了,这个其实没有问题。但是老师又提出了问题,如果在concept页面里面还有动态内容,该怎么办?还需要创建更多的文件夹吗?

那么这时候就引出了这一节需要学习的内容:catch-all segments。可以在某个文件夹里面,比如说 docs 文件夹里面,创建一个[...slug]文件夹,里面就可以捕获 /doc 后面所有使用 / 拼接的动态路由参数,无论多少个参数。

image-20240830100846055

假设我们有20个features,每个feature都有20个concepts,那么就有400个路由文件夹,如果将concept和feature都做成动态路由,那么只需要一个路由文件夹,用catch all segments来实现。那么如果在concept下面还有动态路由,只需要在这个文件夹里面做动态路由就行了。

这个概念非常重要,简直就是把CRM开发的模板做出来了。

 

我上面的这句话是什么意思?隔了一年我都不知道是什么意思了。上面这个说法其实是想说:通过左侧的菜单,然后控制右侧的显示内容,就像我经常做的若依后台管理系统一样。

但是这种需求到底是否适用于catch-all segments的用法,我难道还要在一个文件夹里面,通过判断路由的参数来展示不同的菜单页面吗?那不是要把整个项目的所有功能页面都引入到这个文件夹里面来?那nextjs的文件系统其实也就没用了,那也太复杂了。或者说我获取到路由参数之后,拼接一个地址,然后导入这个组件?nextjs支持这样吗?

这一点其实还需要商榷,以后可以看一下是否可行。

具体的使用场景还是需要我找一下。(2025-09-08)

在app里面创建docs文件夹,docs文件夹里面创建[...slug]文件夹,里面创建page.tsx文件,编写组件。这里的[...slug]里面的...对于nextjs来说是特殊的符号,表示用于创建捕获所有路径的动态路由,slug是文件夹名,是一个共同约定,英文原意是小毛虫。

在 Next.js 中,文件夹名称中包含的 [...] 语法是一种动态路由的表示方式,而 ... 是用于创建捕获所有路径的动态路由。

... 在 Next.js 中的作用:

[...slug] 具体含义:

如果用户访问 /blog/a/b/c,那么 router.query.slugs 将会是 ['a', 'b', 'c'],组件会渲染出 Slugs: a/b/c

总结:

通过使用 [...slug],你可以创建一个非常灵活的路由规则,适用于处理多层嵌套的动态路径结构。

这样做了之后,如果url中以域名/docs开头而且后面还有路径的(/doc这个路由会匹配到/doc/page.tsx这个页面,如果没有这个文件,会返回not found),那么就可以匹配到这个页面,下面试一下:

注意:老师在视频中说的并不准确,视频中说任何contain docs的路由,都会被匹配,那么我就试一下,是不行的。

image-20250908145923465

应该是starts with doc and its top route,才准确。

 

上面的案例中,因为docs文件夹下没有page.tsx文件,所以localhost:3000/docs路由没有匹配。

那么如果接收到具体的参数值呢?localhost:3000/docs/feature1/concept1/example1,这里的feature1、concept1、example1都是param,怎么接收呢?还是使用props来接收,此时接收的params是一个数组。

看一下效果:

 

代码其实解决了场景6中查看右侧展示区的问题,左边的菜单栏其实就是slugs数组的数据源,给定具体的路由地址,然后展示相应的信息。

optional catch all segments

通过上面的展示,我们知道访问localhost:3000/docs会报404,因为docs文件夹里面没有page.tsx文件,此时可以在[...slug]外面包裹一层[][[...slug]],形成optional catch-all segments语法。此时就会走[...slug]/page.tsx里面最后的return语句了。

image-20240830104924065

那么提出了一个问题:我既然可以在docs文件夹下面创建一个page.tsx来显示,但是我其实在[[...slug]]/page.tsx里面已经有了适配情况了,那么两种方式在什么情况适用呢?

其实还是很好判断的,如果/docs这个页面是个静态页面的话,就使用docs/page.tsx;如果/docs这个页面需要根据不同url展示一些不同信息的话,那么最好写在[[...slug]]/page.tsx中,因为此时可以接收到具体的参数。

这里仔细想一想,还是解决了很重大的问题的,使用好了还是蛮方便的。

动态图示:

10- Not Found Page

这节课来学习自定义404页面。之前我们已经知道了,当访问了一个app中并不存在的文件夹对应的路由时,nextjs提供了默认的404页面,但是有时候我们想自定义404页面,做的更具体更好看一些,下面是解决方法。

1、not-found页面

在app文件夹里面创建一个not-found.tsx文件,文件的名称必须为not-found,编写组件。

看一下效果:

image-20240830110119506

样式可以自己调整,这里的效果已经出来了。

 

2、notFound函数

但是如果我想在js代码里面,使用函数来触发显示这个页面,该怎么做呢?可以使用notFound函数,下面是一个例子。

例子:如果我想在reviewId大于1000的时候,展示notFound页面,该怎么做呢?

首先在[reviewId]文件夹里面创建not-found.tsx文件,编写组件。

然后在page.tsx里面引入not-found.tsx文件,并写判断条件:

需要注意:是从next/navigation里面引入的notFound,而且虽然not-found.tsx里面定义的组件名是NotFound,但是这里必须写notFound,这是nextjs约定的。

查看效果:

虽然说使用的是notFound函数,但它实际上是跳转到一个not-found页面的。所以必须在这里有一个not-found.tsx文件。我看了一下文档,是这样的。

image-20250924115826603

 

not-found文件里面是不能接收props参数的,那么有时候确实需要从url接收参数来显示不同的提示,该怎么办呢?此时就用到nextjs提供的hooks,叫做:usePathname

写到这里,页面报错了:

image-20250908153941701

具体报错信息:You're importing a component that needs usePathname. This React Hook only works in a Client Component. To fix, mark the file (or its parent) with the "use client" directive.

这个意思是说,usePathname是一个hook,在第一节我们就知道了,nextjs里面所有的组件都默认是server component,是不能使用react hooks的,当然nextjs hooks也属于react hooks,所以这里想要使用hook,就必须是一个client component。怎么变成client component呢?需要在file顶部加上"use client";

有多个not-found文件,nextjs应该是使用了就近原则,为我们展示不同的页面。

11- File Colocation

lesson-11、12、13,这三节课都是在讲怎么组织代码文件。file colocation是nextjs内置提供的特性,不需要额外的操作就可以实现;private folders和route groups都需要额外的约定来操作。

colocation,英文意思是托管。虽然nextjs提供了基于file-system的route的规则,但是也可以灵活的去组织文件和文件夹。

each folder represents a route segment mapped to a corresponding segment in the URL path, but this is important, a route only becomes publicly accessible when you add a page.js or page.tsx file to it.下面的案例就是解释这句话的:

案例:在app里面新建dashboard文件夹,创建line-chart.tsx文件,编写组件。

查看效果:

image-20240830190431130

原因我们已经知道了,就是dashboard里面必须要有page.tsx文件,才能映射到这个路由地址。

于是我们创建page.tsx文件,编写组件。

查看效果:

image-20240830190900040

原因是需要default export 一个react component,然后改成下面这样:

查看效果:

image-20240830191027833

上面这个过程非常必要,并不是废话,而是展示了在dashboard文件夹中,如果我们创建别的文件或组件,并不会对page.tsx中default export出去的component造成影响,是安全的,也就是说我们可以在dashboard中编写复杂的逻辑组件,最后通过这个default export的组件暴露出去。

改成这样看一下:

查看效果:

image-20240830192218488

这样,我们组织复杂组件就非常简单了,可以选择在某个文件夹中创建一些组件,这些组件并不会影响到page.tsx。但是nextjs并不是所有的组件都必须写在app文件夹中,与app文件夹同级可以创建一个components文件夹,里面放一下全局的UI组件完全没有问题。nextjs提供了两个特性来帮忙组织代码,以后会讲到。

12- Private Folders

上面一节讲解了nextjs提供的out-of-box的safe collocation of files的方式,这一节我们要学习另一个很酷的nextjs feature,这个特性可以帮助我们很有条理的组织代码。

image-20250908160348176

为了创建一个私有文件夹,这个文件夹的名称的前缀必须是underscore(下划线)。

在app文件夹中创建_lib文件夹,里面创建format-date.ts文件,表示这里面的一些公共函数文件,这不是重点。重点是在这里创建一个page.tsx,里面编写组件,看能否访问。

查看效果:

image-20240830193245729

不能访问。原因是_lib是私有文件夹,不能被添加到路由系统。私有文件夹有以下这些应用场景:

image-20250908160617178

老师提供了一个练习,使用 %5F 来代替_,重新访问/%5Flib,看一下效果,答案是不行:

最后老师提示,private folders is just one of the ways to organize your nextjs project, if you don't like it, you can simply rely on file collocation, or even place files outside of the app folder.

13- Route Groups

这是nextjs提供的第二个帮助我们组织代码特性,route groups。这一节的重点在于,将一些功能类似的页面可以组织在一起,比如说权限相关的页面,如果是按照之前的方法,那么就需要在app文件夹里面创建三个文件夹,但是使用了route groups之后,就可以只创建一个auth文件夹,将权限相关的文件夹都放到auth文件夹里面,并且URL访问时可以忽略auth这个地址。

image-20250908161801448

It is also worth noting that Route Groups are actually the only way to share a layout between routes without affecting the URL.这句话值得重视,route groups是nextjs中唯一能够实现共享layout而不影响url的方式。

在app文件夹中创建register、login、forgot-password文件夹,分别创建page.tsx,创建组件。

查看效果:

效果是OK的,但是register、login、forgot-password都是authentication相关的代码,现在很分散,能不能放在一起呢?这样在一个team里面,别人找也好找一些。a good developer manages the project files into groups based on sections or intent.

所以可以在app下创建auth文件夹,将上面这些文件夹全部放到里面去。

image-20240830195058918

那么我们就需要使用这样的路由地址来访问了:localhost:3000/auth/login,这些地址对于marketing人员、analytics人员来说并不友好,网址越短越好记,解决办法就是使用route groups,将这个文件夹排除在route system之外。怎么创建route groups呢?就是在文件夹名外面包裹一层小括号。

image-20240830195841578

这样直接访问localhost:3000/login这些地址就可以了。

如果你想要更多的结构,比如说auth里面的代码文件很多,还可以使用nested route groups,嵌套路由组,能够组织更加复杂的代码。

14- Layouts

学习了上面的课程之后,我有一个疑问,那就是在app里面的page.tsx不能直接渲染,必须要有一个layout.tsx,但是app文件夹里面的子文件夹里面的page.tsx,就可以单独存在,不需要一个layout.tsx,这是为什么呢?希望你学习完了之后可以回答这个问题。

 

之前讲了pages,接下来要讲的是layouts,下面是二者的不同概念。

image-20250908163913109

上图的案例中,像Header和Footer就是layouts,content对应的就是pages。

那么怎么创建layouts呢?通过创建layout.js或者layout.tsx文件,里面默认暴露一个react component。

image-20250908164051293

在编写自定义的layouts之前,来看一下nextjs强制提供的layout.tsx文件,这是项目的root layout文件。之前我们已经知道,即使删除了这个layout.tsx文件,在启动项目的时候,nextjs都会自动创建一个src/app下面的layout.tsx文件。

每一个layout.tsx里面的默认组件,都会接收children prop,这里的children prop就是当前路由对应的page.tsx文件里面的默认暴露的component,动图可以仔细看一下,不同的路由展示不同的组件。当项目刚启动的时候,默认的children就是src/app/page.tsx的组件。

下面将layout.tsx组件改一下,看一下效果,可以看到header和footer是保持不变的,无论访问的是哪个路由地址(只有找不到路由地址时,会显示404或设置好的not-found页面):

动态展示:

小结:

这节课介绍了layouts的概念,但是只讲了nextjs强制提供的一个layout.tsx文件,通过修改这个文件,我们可以知道layout里面可以怎么组织代码。但是还没有讲怎么创建自定义的layout文件,relax, it's upcoming.

15- Nested Layouts

上一节我们已经学习了layouts的概念,a layout is UI that is shared between multiple pages in your app,并且我们知道了nestjs里面有一个强制的layout文件,就是app下面的layout文件。这一节我们学习嵌套的layouts。

这里用案例说明,Let's say you want a special layout just for your product details pages, we can do that by adding a layout.tsx file inside the product details folder.

[productId]文件夹里面创建layou.tsx文件,编写组件。

这个layout.tsx文件corresponds to the productId page.tsx文件。

image-20240830203531644

查看效果,会发现出现了Featured products这个h2标题:

那为什么当访问product详情时,会展示layout.tsx里面的内容?这是因为渲染流程是这样的:

当访问localhost:3000/products时,app/layout.tsx里面的children是products/page.tsx里面的默认组件。当访问localhost:3000/products/1时,由于products/[productId]文件夹里面有layout.tsx文件,所以这个文件里面的默认组件会被当做app/layout.tsx里面的children,最后,product/[productId]/layout.tsx里面的children,就是product/[productId]/page.tsx的默认组件,所以展示的信息就是这样。

image-20240830212450569

nested layout gives you the power to create specialized layouts for different parts of your application.

动图:

小结:

这节课讲了nested layout,nested layout可以让我们在项目的某个特定区域创建layout UI。前提是要搞清楚整个渲染流程。

16- Route Group Layout

在14小节中,我们在app下的layout.tsx里面加入了header和footer,这样所有的页面都会显示header和footer,但是有一些页面,比如说登录、注册页面,我们不想显示header和footer,该怎么做呢?这时需要使用route gourp layout。

之前学习了route group,作用是什么?是为了将一些页面能够组织在一起,避免直接放在app下面,于是我们创建了auth文件夹,里面有login、register、forgot-password这些页面,同时我们将文件夹名改为(auth),就让url访问的时候,可以不写auth。

其实方法就是使用多个root layout,root还可以有多个吗?是的,nextjs帮助我们实现了。使用的是route group layout方法。

image-20250908171823594

假设我们的app有两部分,一部分就是auth,另一部分就是marketing,auth里面的页面不需要header和footer,但是marketing里面的页面都需要,原始结构如下:

image-20250908191158630

1、create two route groups in the app folder, marketing and auth. move customers folder and revenue folder into marketing folder, move login and register folder into auth folder.

image-20250908191300932

2、Move root layout.tsx file into marketing folder, change this component name to MarketingLayout.

image-20250908191358498

3、copy and paste the layout.tsx file in the marketing folder to auth folder, change the component name to AuthLayout. And delete the header and footer code.

image-20250908191436534

先执行看一下效果:

image-20250908191713151

但是老师的报错是这种:

image-20250908191704197

但我还是先按照老师的方法改一下,就是将 app/page.tsx 文件移动到marketing文件夹中去:

image-20250908191849643

结果可以了:

小结:

这节课实际上有两个概念,route groups 和 layout,二者是结合使用的。首先使用route groups创建一个文件夹,当nextjs访问这个文件夹里面的内容时,会先访问layout.tsx,那么里面的children就是该文件夹里面的子文件夹里面的page.tsx的默认组件,这是nextjs的流程,就是这样设计的,搞清楚流程即可,照着做。

和单纯的route groups还是不同的,要仔细体会这种不同。

 

这里还有一个问题,为什么只需要在(marketing)文件夹里面放page.tsx文件呢?(auth)文件夹里面不放为什么可以呢?

我想应该是这样的,当访问根路径的时候,nextjs会寻找layout.tsx,遇到里面的{children},会寻找里面的page.tsx文件。当在(auth)文件夹里面的寻找时候,发现没有,它会先判断有没有另外一个route group,还是按照同样的方法来寻找,发现(marketing)里面有,于是就渲染了。

17- Routing Metadata

image-20250908192309680

上面的意思:元数据确保我们的内容在被搜索引擎共享或索引时看起来很棒。这里的“我们的内容”指的是什么?“看起来很棒”是什么意思?我搜索了一下:

在 Next.js 中,metadata 是用于定义页面元数据的机制,主要作用是向浏览器、搜索引擎和其他服务提供关于页面的关键信息。这些元数据对于 SEO(搜索引擎优化)、社交媒体分享、浏览器行为控制等至关重要。

具体来说,metadata 的核心作用包括:

  1. SEO 优化 定义页面的标题(title)、描述(description)、关键词(keywords)等信息,帮助搜索引擎理解页面内容,提升搜索排名。
  2. 社交媒体分享优化 配置 Open Graph(如 Facebook、LinkedIn)和 Twitter Card 等元数据,使页面在社交平台分享时能正确显示标题、描述、缩略图等内容。
  3. 浏览器行为控制 例如定义字符编码、视口设置(viewport)、缓存策略、页面图标(favicon)等,影响浏览器对页面的渲染和处理方式。
  4. 结构化数据 可以包含 JSON-LD 等结构化数据,帮助搜索引擎更好地解析页面内容(如文章、产品信息等)。

总结一下就是,metadata好像与开发无关,但是与整个项目、产品是关系很大的。写起来应该就是照着产品设计来做就行了。

image-20250908193454479

从上面的metadata rules可以看出,layout.tsx和page.tsx文件中都可以定义metadata,如果是相同的route有多个metadata,那么会合并;如果metadata有相同的属性,那么page.tsx里面的metadata会覆盖layout.tsx里面的metadata属性。

1、Static metadata

下面是一个例子,回到了routing-demo项目中:

保留layout.tsx里面的metadata:

查看:

image-20240831193333185

接着在app/about/page.tsx里面编写metadata。

当访问localhost:3000/about的时候,title属性就变为了app/about/page.tsx里面定义的metadata的title的属性值了。

image-20240831193501865

nextjs里面处理metadata的原则就是:when routes have multiple metadata objects, they merge together with deeper segments taking priority。所以显示的是about页面定义的metadata。

2、dynamic metadata

dynamic metadata depends on dynamic information ,such as current route parameters, external data or metadata in parent segments.

为了定义一个dynamic metadata,我们需要export 一个 metadata function that returns a metadata object from a layout.tsx or page.tsx。

这里以[productId]/page.tsx里面暴露动态metadata作为例子,暴露出里面的productId。

看一下效果:

image-20240831194953055

在真实案例中,可以从数据库得到真实数据渲染,比如说此时要fetch data什么的。下面是一个模拟的例子:

3、使用metadata需要注意的

1、static metadata和dynamic metadata不能定义在同一个文件里面。

2、metadata will not work in pages that are marked with "use client" directive。也就是说,metadata在client components里面无法使用。

下面给出注意点2的示例,创建一个counter页面,里面使用"use client",看metadata是否起作用。

页面报错,报错信息:You are attempting to export "metadata" from a component marked with "use client", which is disallowed. Either remove the export, or the "use client" directive.

image-20250908200801478

那是不是就没有办法解决了呢?这个页面我就是要设置一个metadata该怎么办?可以这样解决:将交互组件的代码抽离到一个文件中,这个组件就是client component,然后在page.tsx引入这个组件就行了。此时paget.tsx是server component,就可以设置metadata。

image-20250908201839727

这里就有一个报错了:

image-20250908202302163

也就是说,不能从server上插入一个client function,要将其作为component来使用。那么我猜就是不能这样使用{Counter()},而要当成标签使用<Counter />,先试一下,果然可以了。完整代码重新发一下:

 

小结:

这节课先讲了metadata的概念,就是为了SEO,有两种类型的metadata,static metadata和dynamic metadata。必须定义在page.tsx或者layout.tsx文件中。

18- title Metadata

这节课重点讲一下metadata里面的title属性。内容看上去有点多,但其实规则很简单。

image-20240831195709696

title属性可以定义为string或者object,在上节课中,我们知道了title可以定义为string类型。

image-20240831195924651

还能定义为object,这种定义方式更加灵活,有三个属性。

下面是三个例子

1、设置default属性时:

注意看顶部tab的title值,当子路由中没有设置metadata的title属性时,会默认展示父级路由中的metadata.title。

2、设置template属性时

可以看到,可以为子级路由的metadata.title设置前缀或者后缀。

3、设置absolute属性

当父级路由设置title的template属性时,在子路由中可以设置absolute的值,会忽略掉父级路由title的template属性值,展示绝对的title值。所以这里在app/about/page.tsx里面设置metadata.absolute的值,注意此时app/layout.tsx里面设置了metadata.template的值,看效果。

可以看到,即使app/layout.tsx里面定义了metadata.template,但是app/about/page.tsx里面定义了metadata.absolute之后,title的值就是固定的了。

小结:

这节课重点讲解了metadata.title的编写方式,有两种,string类型或者object类型。其中object类型有三个属性:default、absolute、template,可以帮助我们编写出想要的title。

19- Link Component Navigation

其实学习到这里我就已经收获很大了,我收获了哪些呢?

代码结构我知道该怎么做了,一个路由对应一个文件夹这是最基本的,这样我就知道组件文件该怎么放、怎么组织。而且第三方或者自定义组件我也知道该放在哪里了,这样就能组织起最基本的项目了。

下面是什么内容呢?是关于路由跳转的内容,有标签跳转和js方法跳转,也是熟面孔了。

在之前的课程中,我们是通过在浏览器url栏中手动改变url来导航到不同的路由地址的,但是在实际操作中,用户是通过点击UI元素或者完成某项操作之后进行导航跳转的,下面会讲解如何编写这样的代码。

image-20250908205115653

比如说下面这个例子,用户点击Blog就可以跳转到localhost:3000/blog,这才是正常的UI操作。

image-20240831202704638

为了能够让用户在操作时进行导航,nextjs提供了Link组件,这是nextjs首推的导航方式。

image-20250910132351734

下面在app/page.tsx里面引入Link组件,尝试Link组件的效果。

1、静态路由

效果:

2、动态路由

href里面传递参数,该怎么办呢?写成这样:

我们知道react里面的表达式可以写在{}中,那么里面可以写模板字符串,传递参数。

效果:

3、replace属性

Link组件上,可以添加replace属性,默认值为true。表示在跳转到这个链接时,是在浏览器的history中替换掉当前的路由地址,所以返回的时候,效果会不一样。

注意看下面点击product100之后,再返回的时候,是直接返回home界面了,说明这里的replace属性起作用了。

 

小结:

这节课主要讲了使用Link组件,来让用户可以使用UI组件来跳转路由。首先要从next/link导入Link组件,通过它的href属性来配置要跳转的路由地址,默认跳转方式是window.history.push的方式,可以通过添加replace属性来做路由跳转的替换。

20- Active Links

这节课主要讲解怎么自定义active link的样式,上节课的案例中可以看到,active link的样式就是点击之后颜色会发生变化,这种样式非常难看,那么这节课就学习怎么编写自定义的active link的样式。

在app/(auth)文件夹里面,新建layout.tsx文件,copy以下代码,不要有心理负担,也可以照抄一遍熟悉一下,这节课的重点是编写自定义active link样式:

这样,在访问auth里面的3个页面的时候,就会展示link组件:

image-20240831212315467

1、怎么确定哪个路由是active link呢?

nextjs提供了usePathname,通过这个hook可以知道active link是哪个。

此时会报错:

image-20240831212907231

原因是只能在client component里面使用usePathname,在第4节课中老师讲了,nextjs中有两种component,可以在文件的顶部使用use client,将组件变为client component。

image-20240831213133414

这样就不会报错了。

2、 通过判断pathname是否包含当前link,可以给Link组件添加样式,这里通过className来设置样式

输出pathname来看一下是什么?pathname represents the url path.

那么就可以这样编写了:

为了查看效果,还需要创建app/(auth)/styles.css文件,将tailwind样式添加进来。并在app/(auth)/layout.tsx里面引入这个样式文件import "./styles.css"

注意:引入tailwind的步骤有变化,现在的tailwindcss是 v4 版本,所以直接看文档就可以解决。

https://tailwindcss.com/docs/installation/framework-guides/nextjs

image-20250910141607380

查看效果:

小结:

这节课主要学习了怎么为active link编写自定义的样式,首先使用usePathname这个hook来找到active link的path,比对当前link和pathname来判断是不是active link,然后通过判断条件为active link添加样式。

额外话

项目在编写过程中,热更新非常慢,每次路由的跳转都会重新下载main-app.js,30-40s。

image-20240831205205074

其实在命令行中已经有报错了:

image-20240831205045804

https://nextjs.org/docs/messages/fast-refresh-reload

打开上面这个地址看一下,它说:

image-20240831205227230

按照它的指示,找了一圈,试着改了一圈,都没有效果。偶然间重新打开一个浏览器窗口,关闭原来的浏览器窗口,输入项目地址,居然就好了,热更新变正常了,这也是个奇迹了。

 

 

要做的事

1、将nextjs的概念总结一下

2、将nextjs和react的hook区分一下

观看教程中学习到的一些方法

framer-motion

这是一个npm库,可以用在react或者nextjs项目中,用来给页面添加动画效果。使用起来非常简单。

vscode快速创建文件夹和文件

直接点击vscode创建文件的图标,输入文件夹名/文件名,然后按enter键,就可以了。