Next.js / React 一些学习笔记

Lab

这篇文章主要来源于我的个人理解,不一定准确,但是我是这样用的(

1. Next.js App Router

提到Next.js的主要组成的的话,我觉得就是路由系统了。Next.js路由写起来很简单,而且很实用,先从文件系统路由来说,其次为动态的路由。

文件系统路由

  • src/app/文件夹里创建文件夹,在Next.js中即算为路由
  • page.tsx文件就是这个路由的页面
  • 比如src/app/about/page.tsx就是/about页面

动态路由

  • 用方括号[xxx]来创建动态的路由,比如/blog/[cid]/page.tsx即为一个动态的路由
  • 然后呢在组件里用useParams()可以获取到这个参数
  • 此界面的实现就是这样的:/blog/123中的123就是所获取到的cid

2. React Hooks

React Hooks 是一种函数式组件的增强机制,它允许你在不编写类组件的情况下使用 React 的特性。主要的 Hooks 包括 useState, useEffect, useContext, useReducer, useCallback, useMemo, useRef, 和 useImperativeHandle 等。这些 Hooks 提供了访问 React 特性的方式。

以下是一些我用到的React Hooks的具体实现

useState - 管理状态

useState Hook 允许你在函数组件中使用局部状态。它会返回一个状态值和更新该状态值的函数。
const [loading, setLoading] = useState(true) // 此处即表示加载状态
const [comments, setComments] = useState([]) // 评论列表

useEffect - 执行副作用操作

useEffect Hook,允许你将组件与外部系统同步(如数据获取、订阅管理、DOM 操作等)。它在每次渲染后都会执行。
useEffect(() => {
  // 页面加载时获取数据
  fetchData()
}, []) // 空数组表示只在组件挂载时执行一次

useRef - 获取DOM元素

用于创建对 DOM 元素或值的引用,可以在渲染之间保持状态。
const textareaRef = useRef(null)
// 可以直接操作textarea元素,比如设置光标位置

3. TypeScript

TypeScript 是 JavaScript 的超集,扩展了 JavaScript 的语法,因此现有的 JavaScript 代码可与 TypeScript 一起工作无需任何修改,TypeScript 通过类型注解提供编译时的静态类型检查。

TypeScript 可处理已有的 JavaScript 代码,并只对其中的 TypeScript 代码进行编译。

定义接口的一个小例子

interface Post {
  id: number
  title: string
  content: string
}

这段代码的意思是:

定义了一个叫 Post 的接口(interface),它描述了一个“帖子”的结构,里面有三个属性:

  • id:编号,是一个数字(number)
  • title:标题,是一个字符串(string)
  • content:内容,也是字符串(string)

这个接口可以用来规范对象的形状,比如下面这样:

const post: Post = {
  id: 1,
  title: "标题",
  content: "这是内容"
}

这样写,TypeScript会帮你检查这个对象是否符合 Post 的结构。

所以说TypeScript的优势就在这里

  • 写代码的时候有智能提示,能提前发现错误,不用等到运行时才知道。
  • 代码会更容易维护。

4. 组件化管理

复杂的页面的往往会出现重复的代码段,在Next.js中我们可以把这些重复的代码段拆分成单个小组件,然后直接引用,这样代码不仅更好管理,代码更加的清晰:

组件拆分的思路
例如我每个页面都有顶栏(navbar),如果每个页面都写重复的navbar代码,改起来便很麻烦。所以就将其拆分为navbar.tsx然后存放于components之中即可。然后页面头部引用该文件。

import { Navbar } from "@/components/navbar"

5.Props传递

interface CommentProps {
  comment: Comment
  onReply: (author: string) => void
}

function CommentItem({ comment, onReply }: CommentProps) {
  // 组件内容
}

这段代码演示了 在 React(Next.js)中通过 Props 向组件传递数据和函数 的方式。

1. interface CommentProps

定义了传给 CommentItem 组件的参数类型(也叫 props)。

  • comment:是一个 Comment 类型的对象,表示一条评论(例如包含作者、内容、时间等)。
  • onReply:是一个函数,接收一个字符串(作者名),用于点击“回复”按钮时执行相应操作。

2. function CommentItem({ comment, onReply }: CommentProps)

这是一个 React 函数组件。

使用了解构语法,从传入的 props 中直接取出 comment 和 onReply。

这样可以在组件内部使用 comment 数据来显示评论内容,也可以在用户点击“回复”时调用 onReply() 来触发父组件的处理逻辑。

6. 数据处理

这里以递归处理评论树来说

在评论系统中,常常会有“评论回复评论”的结构,比如:

- 评论 A(id: 1)
  - 回复 A1(parent: 1)
    - 回复 A1-1(parent: A1)
  - 回复 A2(parent: 1)、

这样的结构是树形的,每条评论通过 parent 字段来指向它的上一级评论。

function getAllReplies(comments, parentId) {
  const replies = []
  comments.forEach(comment => {
    if (comment.parent === parentId) {
      replies.push(comment)
      // 递归查找子评论
      replies.push(...getAllReplies(comments, comment.id))
    }
  })
  return replies
}

这段代码便是找到某个评论(parentId)下的所有“直接和间接”子评论,并把它们放在一个数组里返回。
假设我们调用:

getAllReplies(comments, 1)

意思是找出「ID 为 1 的评论」下面的所有子评论。

那函数怎么做的呢?

  • 1.遍历每条评论
  • 2.如果某条评论的 parent === 1(说明它是 ID 为 1 的直接回复)
  • 3.把它加进 replies 结果数组里
  • 4.然后递归调用自己:去找这条子评论的“子评论”
  • 5.一直递归下去,直到找不到更多子评论为止
  • 6.最后返回一个包含所有层级子评论的扁平数组

7. 表单处理

React的表单处理有自己的套路。它处理表单和原生HTML有些不同,核心思想是:用组件的状态(state)来控制输入框的值,这就是“受控组件”的概念。

受控组件

const [form, setForm] = useState({
  name: '',
  email: '',
  message: ''
})

<input 
  value={form.name}
  onChange={e => setForm({...form, name: e.target.value})}
/>

注意

  • useState 是 React 的一个 Hook,用来声明状态。 form
  • 是一个对象,包含三个字段:name、email、message,分别对应输入框的值。
  • setForm 是更新 form 的函数。

上半段代码表示:我们要用 form 这个 state 来控制输入框的值,每个输入框的内容都保存在 form 里。
而下半段即是把所有表单数据都保存在 state 里,我们可以随时查看、验证、提交。

表单提交

const handleSubmit = async (e) => {
  e.preventDefault() // 阻止默认提交行为
  try {
    await fetch('/api/submit', {
      method: 'POST',
      body: JSON.stringify(form)
    })
    alert('提交成功!')
  } catch (error) {
    alert('提交失败!')
  }
}

在这段代码中呢

  • handleSubmit 是你绑定在
    上的提交事件处理函数。
  • e.preventDefault():阻止表单默认的提交行为(不刷新页面)。
  • fetch('/api/submit', { ... }):用 JavaScript 发起 POST 请求,把表单数据(form)发送到后端。
  • JSON.stringify(form):把表单对象转成 JSON 字符串。 alert('提交成功!'):提交成功后弹出提示。
  • 如果出错(例如网络问题或服务器异常),就会进入 catch 显示“提交失败”。

8. 对性能进行优化

动态导入是指在用户访问页面时,根据需要按需加载组件,而不是在初始页面加载时将所有组件都打包。这种方式可以显著优化性能和用户体验。

// 组件懒加载,减少首屏加载时间
const MarkdownEditor = dynamic(() => import('./MarkdownEditor'), {
  ssr: false // 不在服务端渲染
})

同时还要避免不必要的重新渲染

  • 比如合理使用useEffect的依赖数组
  • 还有事件处理函数记得清理,避免内存泄漏

这些是我在学习Next.js/React的一些笔记与总结,不一定完全对awa(欢迎指正)。也算是一些记录,之后或许会继续更新(

5 条评论

    1. p
      ponyjun 07-17 22:24

      这是一个我的评论,你好来自中国的朋友yang,非常很高兴的见识到你,谢谢!

      回复
      1. y
        yang 07-17 22:36

        嘿嘿

        回复
    2. f
      fly6022 07-17 22:29

      ::furry:7::

      回复
      1. y
        yang 07-17 22:37

        ::furry:15::

        回复
      2. y
        yang 09-01 10:00

        嘻嘻::furry:9::

        回复

发表评论