# 学习资料 https://u19tul1sz9g.feishu.cn/docx/WEWJdSzF5oTnwvxHGGAc0Vojnxe?from=from_copylink 密码:M6923&65 # 关于 Node 的理解 | Node.js | Java | | --------------- | ----------- | | Node.js version | JDK version | | V8 Engine | JVM | | Npm | Maven | | N-API | JNI | ``` ┌───────────────┐ │ JS APP │ └───────▲───────┘ │ ┌───────┴───────┐ │ NPM │ ← 包管理 & 生态 └───────▲───────┘ │ ┌───────┴───────┐ │ Node.js │ ← Runtime(API / EventLoop / Libuv) └───────▲───────┘ │ ┌───────┴───────┐ │ V8 │ ← JS 引擎 └───────▲───────┘ │ 操作系统 ``` ## Node.js 版本 [Node.js](https://nodejs.org/zh-cn/about/previous-releases) 采用固定节奏发布 + LTS 生命周期,每 6 个月发布一个,相当于每年会覆盖一个 LTS。 # 第一章 开发环境与核心概念 初始化环境 ```bash pnpm create vite@latest basic2 --template react-ts ``` 所谓的优雅公式:`UI = f(State)`,用户界面仅仅是应用程序状态的一个函数。 JSX 不是 HTML 而是 JavaScript 的一种特殊语法。我们编写的每一行 JSX 代码最后都会被转换为一个函数:`React.createElement()` > 例如: > `

Hello React

` > 对应: > `React.createElement('h1', { className: 'title' }, 'Hello React')` 可以使用 `{ }` 在 JSX 中嵌入任何 JavaScript 表达式(变量、数学、函数)。 关于声明: | 关键字 | 作用域 | 重复声明 | 是否可以修改引用 | 推荐场景 | | ----------- | ---------------- | ---- | -------- | -------------------------- | | **`const`** | 块级作用域 (Block) | 不允许 | 不允许 | **默认使用**,除非变量需要重新赋值 | | **`let`** | 块级作用域 (Block) | 不允许 | 允许 | 用于循环变量或需要修改引用的场景 | | **`var`** | 函数作用域 (Function) | 允许 | 允许 | **严禁使用** (旧时代的产物,存在变量提升问题) | 一个组件的返回必须有一个**单一的根元素**,如果返回并列的多个元素,可以嵌套一个 `
`,但更好的做法是使用 `Fragment`,语法糖是 `<>`。因 JSX 最终是会被编译为 JavaScript,所以要注意不要产生关键字的冲突。这也是为什么 `class` 在 React 中要写成 `className`,同时时间名要遵循驼峰命名法,例如 `onClick`。 **导入方式** 具名导入: ``` import { ... } from 'react' ``` 默认导入: ``` import ... from 'react' ``` 副作用导入: ``` import './index.css' ``` React 历史写法: 这里我还是不是很理解 `(prevState) => ({ count: prevState.count + 1 })` 这个的原理,目前的理解是,他可以拿到自己作用域的 count。 ```tsx import React from 'react' interface CounterState { count: number } class ClassCounter extends React.Component { state = { count: 0 } handleClick = () => { // this.setState({ count: this.state.count + 1 }) this.setState((prevState) => ({ count: prevState.count + 1 })) } render() { return (

Class Counter

) } } export default ClassCounter ``` useState 我理解就是有了一个动态更新值的作用。 ```tsx import { useState } from 'react' const FunctionalCounter = () => { const [count, setCount] = useState(0) const handleClick = () => { setCount((prevCount) => prevCount + 1) setCount((prevCount) => prevCount + 1) } console.log(count) return (

Functional Counter

) } export default FunctionalCounter ``` # 第二章 组件化开发核心 Props 通信(只读的,子组件不可以进行修改,单向数据流。) ```tsx type Props = { name: string } const PrintNmae = (name: Props) => { return (

Welcome {name.name}

) } export default PrintNmae ``` 普通传参 ```tsx ``` children 传参,这里 type ```tsx import React from 'react' type CardProps = React.PropsWithChildren<{}> const Card = ({ children }: CardProps) => { return (
{children}
) } export default Card ``` 关于 `{ children }: CardProps` 是组件接收一个 props 然后从里边结构出来 children 类型声明: ```tsx type UserProps = { name: string age: number isVerified: boolean hobbies?: string[] } export const User = (user: UserProps) => { const { name, age, isVerified, hobbies } = user return (

{name}

Age: {age}

校验: {isVerified ? '已验证' : '未验证'}

{hobbies && hobbies.length > 0 &&

爱好: {hobbies.join(', ')}

}
) } ``` 关于 TypeScript 定义 Props 类型: ```tsx type UserProps = { name: string age: number isVerified: boolean hobbies?: string[] } export const User = (user: UserProps) => { const { name, age, isVerified, hobbies } = user // 这里是解构的意思。 return (

{name}

Age: {age}

校验: {isVerified ? '已验证' : '未验证'}

{hobbies && hobbies.length > 0 &&

爱好: {hobbies.join(', ')}

}
) } ``` 事件处理和合成事件系统 这里相当于把函数当作了 Porps,此时实现了子组件决定函数的调用,但是父组件可以控制状态。 ```tsx export const Button = () => { const handeClick = () => { alert('按钮触发了事件') } return } ``` 这里我们自己实现一个父子组件函数通信的能力。这里相当于我们自己声明了一个类似 onClick 的子组件。 ```tsx type LoginButtonProps = { onLogin: () => void } export const LoginButton = ({ onLogin }: LoginButtonProps) => { return } ``` > 这里的时间对象不是原生浏览器对象,是一个合成事件。 useState ```tsx import { useState } from 'react' const Counter = () => { const [count, setCount] = useState(0) const handelClick = () => { setCount(count + 1) } return (

Counter

Count: {count}

) } export default Counter ``` 这里 `setUser` 要用一个新的对象,否则话是不会生效的。 ```tsx import { useState } from 'react' const ErrorState = () => { const [user, setUser] = useState({ name: 'tianzhuo', age: 20 }) const handelClick = () => { setUser({ ...user, age: user.age + 1 }) } return (

ErrorState

Name {user.name}

Age {user.age}

) } export default ErrorState ``` 三元运算符 ```tsx import { useState } from 'react' export const Login = () => { const [isLogin, setIsLogin] = useState(false) return (

{isLogin ? 'Welcome Back!' : 'Please Login'}

) } ``` `&&` 标签显示问题 ```tsx export const MaillBox = ({ messge }) => { return (

MailBox

{messge.length > 0 &&

You have {messge.length} unread messages.

}
) } ``` 代办 ```tsx const todos = [ { id: 1, tesx: 'Learn React' }, { id: 2, tesx: 'Learn TypeScript' }, { id: 3, tesx: 'Build a React App' }, ] export const TodoList = () => { return (

Todo List

    {todos.map((todo) => (
  • {todo.tesx}
  • ))}
) } ``` ## hook 生命周期 因为 StrictMode 的关系,这里会展示两次挂载。 同时如果依赖数组如果是空的话,只会渲染一次。 ```tsx import { useState, useEffect } from 'react' export const UserProfile = ({ userId }) => { const [userData, setUserData] = useState(null) useEffect(() => { console.log('Fetching user data for userId:', userId) const timer = setTimeout(() => { setUserData({ name: 'John Doe', age: 30 }) }, 1000) return () => { clearTimeout(timer) console.log('🧹 定时器已清理') } }, [userId]) if (!userData) { return
Loading...
} return (

User Profile

Name: {userData.name}

Age: {userData.age}

) } ``` hook 的更新 这里相当与用 useState 触发了依赖数组的更新。只得关注的是每变化的时候,是先执行上一次的 clean。 ```tsx import { useState, useEffect } from 'react' export const UserProfile = () => { const [userId, setUserId] = useState(1) // ← 当前用户ID const [userData, setUserData] = useState(null) // 模拟不同ID返回不同数据 const mockUsers = { 1: { name: '张三', age: 28 }, 2: { name: '李四', age: 35 }, 3: { name: '王五', age: 42 }, } useEffect(() => { console.log(`🚀 开始请求 userId: ${userId}`) const timer = setTimeout(() => { setUserData(mockUsers[userId] || { name: '未知用户', age: 0 }) console.log(`✅ 数据加载完成!当前用户: ${mockUsers[userId]?.name}`) }, 800) // 清理函数(StrictMode 会展示) return () => { console.log(`🧹 清理上一次的定时器 (userId: ${userId})`) clearTimeout(timer) } }, [userId]) // ← 关键!依赖 userId if (!userData) { return
加载中...
} return (

用户资料(当前 ID: {userId})

姓名:{userData.name}

年龄:{userData.age}


) } ``` hook 常见问题 1. 无限循环 ```tsx import { useState, useEffect } from 'react' export const BadExample = () => { const [count, setCount] = useState(0) useEffect(() => { console.log(`🔄 Effect 执行了!当前 count = ${count}`) // 这里更新了 count,而 count 又是依赖项 setCount(count + 1) // ← 罪魁祸首! }, [count]) // ← 依赖了 count return (

无限循环演示

当前 count: {count}

看控制台!页面会疯狂卡顿,count 一直加!

) } ``` 2. 忘记放依赖项。 useRef 这里放的是 input ```tsx import { useRef, useEffect } from 'react' export const RefExample = () => { const inputRef = useRef(null) useEffect(() => { inputRef.current?.focus() }, []) return (

useRef 示例:自动聚焦输入框

) } ``` 动态数据存储 ```tsx import { useRef, useState, useEffect } from 'react' export const Search = () => { const [query, setQuery] = useState('') const timeOutRef = useRef(null) useEffect(() => { timeOutRef.current = setTimeout(() => { console.log('搜索:', query) }, 500) return () => { console.log('清除上一次的定时器') clearTimeout(timeOutRef.current) } }, [query]) return ( setQuery(e.target.value)}> ) } ``` ## 第二部分 新老表单 ```tsx export const OldForm = () => { const handleSubmit = (e) => { e.preventDefault() // 这里是为了阻止表单提交默认的动作。 const formData = new FormData(e.target) const name = formData.get('name') console.log(name) } return (
) } ``` ```tsx export const NewForm = () => { const handleSubmit = async (formdata: FormData) => { // 异步操作 const name = formdata.get('name') console.log(name) await new Promise((resolve) => setTimeout(resolve, 1000)) } return (
) } ``` useActionState,这个我理解其实是一个对历史功能的封装优化。简化了自己需要声明很多的 state。 ```tsx import { useActionState } from 'react' export const UseActionState = ({ productId }) => { const addToCart = async (previousState, formData) => { const quantity = formData.get('quantity') console.log('Added to cart') const result = await addToCart1(productId, quantity) if (result.success) { return { success: true, message: 'Product added to cart successfully!' } } else { return { success: false, message: 'Failed to add product to cart.' } } } const addToCart1 = (productId, quantity) => { return new Promise((resolve) => { setTimeout(() => { resolve({ success: true }) }, 1000) }) } const [state, submitAction, isPending] = useActionState(addToCart, null) return (
{state?.message &&

{state.message}

}
) } ``` useformState 可使用 useFormState 获取父组件的表单状态。 ```tsx import { useFormStatus } from 'react-dom' const SubButton = () => { const { pending } = useFormStatus() return ( ) } export const NewForm = () => { const handeSubmit = async (formData) => { const name = formData.get('name') console.log('Form submitted with name:', name) await new Promise((resolve) => setTimeout(resolve, 2000)) console.log('Form submission completed') } return (
) } ``` use 这里的一个想法是实现了层级 fallback ```tsx import React, { Suspense, use } from 'react' import { ErrorBoundary } from 'react-error-boundary' function fetchUser() { return new Promise<{ name: string }>((resolve, reject) => { setTimeout(() => { const success = false if (success) { resolve({ name: '张三' }) } else { reject(new Error('获取用户失败')) } }, 2000) }) } function UserInfo({ userPromise }: { userPromise: Promise<{ name: string }> }) { const user = use(userPromise) return

用户名:{user.name}

} export default function App() { const userPromise = fetchUser() return ( 加载失败了

}> 用户加载中...

}>
) } ``` --- | 模式 | 英文 | 中文 | 类比 | 特点 | SEO | | --- | ----------------------- | ----------- | ---------------- | -------------------- | -------- | | CSR | Client-Side Rendering | 客户端渲染 | 外卖(现点+等) | 慢启动,但灵活 | ❌ | | SSR | Server-Side Rendering | 服务端渲染 | 餐厅现做 | 平衡(快+动态) | ✅ | | SSG | Static Site Generation | 静态站点生成 | 预制菜 | 极快,但不灵活 | ✅ | | RSC | React Server Components | React 服务端组件 | 后厨分工(部分菜在厨房直接处理) | 组件在服务器执行,不进浏览器,减少 JS | ⚠️(间接有利) | # CSS 顶级作用域 ``` :root { ``` 媒体查询 ``` @media (prefers-color-scheme: light) { } ``` ID 选择器 ``` #root ```