react
一、钩子函数
1.创建React项目
npx create-react-app react-basic名
npm i -D sass
npm i antd//组件库(查看文档,根据具体需求修改)
配置别名路径@=src:配置craco.config.js 修改命令
样式初始化 npm i normalize.css
图渲表染 echarts
2.结构一样时:map方法遍历渲染列表,遍历谁给谁key

3.JS代码中编写HTML 多行时可用括号包起来(标签)
- <> </> 简写空标签
简洁,日常开发最常用
不支持任何属性,不能传 key
return (
<>
<h1>标题</h1>
<p>内容</p>
</>
)
- <Fragment> 完整组件
可以接收 key 属性
循环渲染列表、需要给分组节点加 key 时必须用它
{list.map(item => (
<Fragment key={item.id}>
<span>{item.title}</span>
<span>{item.time}</span>
</Fragment>
))}
Fragment 用于包裹多个并列节点,不生成真实 DOM,简化dom结构;
<> </> 是 Fragment 语法糖,无法传递 key;
4.{} 识别 JavaScript中的表达式( 字符串、javaScript变量 、函数调用、JavaScript对象)
React 为什么要用 JSX?
JSX 是 React.createElement 的语法糖,把 HTML 结构写进 JS 代码,浏览器不能直接识别
能将页面 UI 结构和 JS 业务逻辑写在同一处,可读性高
贴合 React 声明式、组件化的开发理念,大幅提升开发效率
支持 JS 表达式插值,无需记忆额外模板指令
5.条件渲染:
- 逻辑与

- 三元

- 自定义函数 + if判断语句
5.事件绑定
on 事件名称 = { 事件处理程序 },遵循驼峰命名法


传出数据用箭头函数


6.组件
一个组件就是首字母大写的函数
7.useState() 渲染、修改、收集、记录数据时使用
向组件添加一个状态变量, 从而控制影响组件的渲染结果


不能直接修改原数据

useState用法
管理组件局部状态,setState 更新是异步批量合并,多次更新会合并执行。
1.存入更新队列
2.判断是否开启批量更新(批量合并规则)
合成事件、生命周期、useEffect 内部:批量更新,多次 setState 合并为一次,只走一次渲染;
setTimeout、原生 DOM 事件、异步请求回调:同步执行,不批量,每次 setState 立即更新。
3.批量合并更新,计算最新 state(浅层合并)
4.生成新虚拟 DOM
5.新旧 vdom 走 Diff 算法对比,标记 DOM 差异。
6.真实 DOM 渲染
7.执行后续生命周期
8.useReducer类似于useState
// 1. 定义reducer纯函数
function countReducer(state, action) {
switch (action.type) {
//传参payload
case 'add':
return { ...state, num: state.num + action.payload }
case 'sub':
return { ...state, num: state.num - action.payload }
default:
return state
}
}
//const [state, dispatch] = useReducer(reducer, initialState)
function Demo() {
const [state, dispatch] = useReducer(countReducer, { num: 0 })
//2.调用dispatch({ type: '' })或dispatch({ type: '', payload: })
return (
<>
<p>{state.num}</p>
<button onClick={() => dispatch({ type: 'add', payload: 1 })}>+1</button>
<button onClick={() => dispatch({ type: 'sub', payload: 1 })}>-1</button>
</>
)
}
9.样式控制
- 类名

- 动态控制类名 (’静态类名‘,{动态类名:条件})

10.受控表单绑定(数据由state管理)
表单 value 绑定组件 state,表单值完全由 React 状态管控,变更通过 onChange 同步;


11.非受控组件(数据由dom管理)在渲染后
不绑定 state,通过 useRef 获取 DOM 原生 value,表单数据由 DOM 自身维护。

useRef 作用:
获取真实 DOM 元素实例;
保存跨渲染周期不变的数据、定时器 ID;
存储组件实例变量,修改不会触发组件重渲染。
| 维度 | props | state |
|---|---|---|
| 归属 | 来自父组件,外部数据 | 组件内部私有数据 |
| 读写 | 只读,子不可修改 | 可读可内部更新 |
| 修改方式 | 父组件更新自身 state 重新传递 | setState /useState 更新 |
| 作用 | 父子通信传值、传方法 | 管理组件动态业务数据 |
| 可传递 | 可以继续向下传给后代组件 | 仅当前组件内部使用 |
12.组件通信
- 父传子:在子组件标签上绑定属性 ,子组件通过props参数接收数据,props是只读对象,props.children表示子标签的内容
- 子传父:父声明含参函数,子标签绑定;子组件中传递解构参数,调用父组件中的箭头函数并传递数据实参

- 兄弟通信:状态提升(先子传父后父传子)、Context、全局状态库
- 跨层通信:Context、Redux/Zustand
Context:
1.使用createContext方法创建一个上下文对象Ctx
2. 在顶层组件(App)中通过 Ctx.Provider 组件提供数据value (标签)
3. 在底层组件(B)中通过 useContext(Ctx) 钩子函数获取 数据
4. value更新,所有消费组件都重渲染
- 任意无关联组件:全局事件订阅、全局状态。
Context 作用
解决多层组件嵌套时多层透传 props 的问题,实现跨层级组件直接共享全局数据,无需每层手动传递参数。适合主题、用户信息这类全局轻量数据,不适合频繁更新、复杂业务状态。
状态提升
当多个兄弟组件需要共享同一份数据时,将共享状态提升到它们最近的共同父组件统一管理,通过 props 分发给子组件,实现兄弟通信。
复杂全局:Redux/Zustand
低频全局:Context
父子、简单跨层:props/状态提升
13.useEffect
组件渲染完毕之后就需要和服务器要数据,整个过程属于“只由渲染引起的操作”,渲染后执行
统一处理所有副作用,如接口请求、定时器、事件订阅、DOM 操作;通过依赖数组控制执行时机;
注意:useEffect 回调不能直接加 async,需在内部单独定义异步函数执行。

当依赖项为函数时,使用usecallback()存函数,防止无效重渲染

14.自定义Hook函数
use命名, 返回仍需使用的状态、方法。
可以通过解构来使用。
规则:
仅能在函数组件顶层或自定义 Hook 内部调用;
禁止在循环、条件判断、嵌套函数中使用;
保证每次渲染 Hook 调用顺序固定。(React 内部用链表存每个 Hook 的状态。按顺序存、按顺序取,所以不能在 if/for 里用,否则顺序乱了,顺序错乱会导致状态映射错误,数据就错了)
自定义 Hooks 必须以 use 开头
15.接口获取数据
- 定义接口文件 放数据
- 定义命令
- 请求数据并渲染
useEffect(()=>{async function- (){await axios.get(‘’),set-() }, -()},[ ])
16.封装和复用
子:封装负责渲染的组件 UI组件
父:当作标签使用
过程涉及通信
状态上提,视图下沉(上层管理状态,下层纯UI复用)
17.性能优化
useMemo:缓存计算结果
//只在依赖数组发生变化时,才重新执行函数计算新值;依赖不变直接复用缓存值。
const cachedValue = useMemo(() => {
// 纯计算逻辑
return 计算结果
}, [依赖1, 依赖2])
useCallback:缓存函数本身
const handleClick = useCallback(() => {}, [])
区别
useMemo:缓存函数计算后的结果,避免每次渲染重复执行昂贵计算;
useCallback:缓存函数引用,防止函数地址频繁变化,配合 memo 避免子组件无效重渲染。
useMemo、useCallback依赖项变化,才会执行
React.memo 是高阶组件,用于缓存函数组件,只有props发生变化时才重渲染组件,减少无效渲染;默认采用浅比较对比新旧 props。父组件传递字面量对象、匿名函数会让浅比较失效,需要 useMemo、useCallback 稳定引用。memo 只能拦截 props 变更,无法拦截自身 state、context 更新带来的重渲染。
浅比较:简单类型比较值;复杂类型比较地址
资源优化:静态资源压缩、图片懒加载、CDN 分发、合理使用浏览器缓存;
渲染优化:减少回流重绘、长列表虚拟滚动、动画使用 transform 硬件加速;
请求优化:接口防抖节流、接口缓存、合并请求;
打包优化:代码分包、路由组件懒加载、第三方依赖 CDN 外置、Tree-Shaking 剔除无用代码;
React 渲染优化:memo、useMemo、useCallback 减少无效重渲染。
18.常用
删除页面数据时,可以使用_.filter(item=>{条件})过滤
tab切换: 1.setstate点击记录 2.遍历,逻辑与匹配,添加类名
点击切换:1.useState 2.绑定onClick
排序:.orderBy(数据,值,方式)
分组:.groupby(数据,条件)
发布评论:即增加数据并渲染,set-(…,{增加的数据})
随机数:uuidV4()
日期格式:dayjs().format(‘YYYY-MM-DD’)
求和:_.reduce((a,c)=>a+c,0)
二、路由
1.框架
- npm i react-router-dom
- 子模块Pages文件夹里创建子文件在index里写组件
- Router/index.js 中导入组件并配置
import { createBrowserRouter } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import NotFound from './pages/NotFound'
// 配置路由表
const router = createBrowserRouter([
{
path: '/',
element: <Home />
},
{
path: '/about',
element: <About />
},
// 404兜底
{
path: '*',
element: <NotFound />
}
])
export default router
- 入口文件 index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider } from 'react-router-dom'
import router from './router'
ReactDOM.createRoot(document.getElementById('root')).render(
<RouterProvider router={router}/>
)
2.二级路由
先创建组件,再配置
//在配置中写children,加上index:true
import { Outlet } from 'react-router-dom'
import Layout from './pages/Layout'
import User from './pages/User'
import UserInfo from './pages/UserInfo'
const router = createBrowserRouter([
{
path: '/user',
element: <Layout/>,
children: [
// 默认子路由 index:true
{ index: true, element: <User/> },
{ path: 'info', element: <UserInfo/> }
]
}
])
在一级组件的index里放 <Outlet /> 渲染子路由
如Layout 组件内部放<Outlet />
先创建,再配置,最后渲染
3.跳转
//跳转链接
import { Link } from 'react-router-dom'
// 替换历史记录(不可回退)
<Link to="/about" replace>关于</Link>
//NavLink,自带路由激活状态,导航菜单
import { NavLink } from 'react-router-dom'
<NavLink to="/user">
{({ isActive }) => (
<span style={{ color: isActive ? 'red' : '#333' }}>用户中心</span>
)}
</NavLink>
//编程式跳转
import { useNavigate } from 'react-router-dom'
const navigate = useNavigate()
navigate('/about')
//编程式组件
import { Navigate } from 'react-router-dom'
<Navigate to="/login" replace />//无登录跳登录页
// 取state参数
const location = useLocation()
const info = location.state
//获取路径 location.pathname
4.路由模式
- Hash 模式
URL 带有 # 哈希锚点,# 后面内容不会发给后端
无需后端配置,#后的内容不会参与 HTTP 请求,服务器只识别 #前面路径,永远匹配根目录资源。
不利于 SEO
静态页面用hash - History 模式
必须后端配置兜底,防止刷新404
SEO 友好
5.Switch / Routes 作用
//Switch只会渲染第一个匹配成功的路由,不会多个路由同时渲染。
//搭配 exact 实现精确匹配,避免前缀误匹配
import { Switch, Route } from 'react-router-dom'
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
{/* 兜底404 */}
<Route path="*" component={NotFound}/>
</Switch>
//<Routes>同样仅渲染匹配的单个路由
//默认精确匹配,不需要写 exact
import { Routes, Route } from 'react-router-dom'
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>}/>
<Route path="*" element={<NotFound/>}/>
</Routes>
不加 Switch/Routes 会怎样?
多个 Route 满足前缀规则时同时渲染多个页面,出现页面重叠。
Switch 模糊匹配;Routes 默认精确匹配,支持嵌套路由,配合 children + <Outlet>
三、redux
1.安装 npm install @reduxjs/toolkit react-redux
2.编写子模块
store/module/userSlice.js
import { createSlice,createAsyncThunk } from '@reduxjs/toolkit'
import axios from 'axios'
const initialState = {
name: '',
age: 18,
info: null,
loading: false,
error: null
}
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
// 同步action
setName: (state, action) => {
state.name = action.payload
},
setAge: (state, action) => {
state.age = action.payload
},
addAge: (state) => {
state.age += 1
}
// 同步清空用户信息
clearUserInfo: (state) => {
state.info = null
state.error = null
},
// 同步修改用户名
updateName: (state, action) => {
if (state.info) state.info.name = action.payload
}
}
// 处理异步状态
extraReducers: (builder) => {
builder
.addCase(getUserInfo.pending, (state) => {
state.loading = true
})
.addCase(getUserInfo.fulfilled, (state, action) => {
state.loading = false
state.info = action.payload
})
.addCase(getUserInfo.rejected, (state, action) => {
state.loading = false
state.error = action.payload
})
}
})
// 异步请求
export const getUserInfo = createAsyncThunk(
'user/getUserInfo',
async (id, { rejectWithValue }) => {
try {
const res = await axios.get(`/api/user/${id}`)
return res.data
} catch (err) {
return rejectWithValue(err.response.data)
}
}
)
// 导出action方法
export const { setName, setAge, addAge } = userSlice.actions
export default userSlice.reducer
3.组合store/index.js
import { configureStore } from '@reduxjs/toolkit'
import userReducer from './slice/userSlice'
export const store = configureStore({
reducer: {
user: userReducer
}
})
4.注入store
import React from 'react'
import ReactDOM from 'react-dom/client'
import { Provider } from 'react-redux'
import { store } from './store'
import App from './App'
ReactDOM.createRoot(document.getElementById('root')).render(
<Provider store={store}>
<App />
</Provider>
)
5.组件中使用数据 + 派发 action
import { useSelector, useDispatch } from 'react-redux'
import { setName, setAge, addAge } from './store/slice/userSlice'
export default function User() {
// 获取state
const { name, age } = useSelector(state => state.user)
//使用函数
const dispatch = useDispatch()
//调用异步
const dispatch = useDispatch()
useEffect(() => {
dispatch(getUserInfo(1))
}, [dispatch])
return (
<div>
<p>姓名:{name}</p>
<p>年龄:{age}</p>
<button onClick={() => dispatch(setName('张三'))}>修改姓名</button>
<button onClick={() => dispatch(setAge(25))}>修改年龄</button>
<button onClick={() => dispatch(addAge())}>年龄+1</button>
</div>
)
}
可用devtools 调试
在很多组件中共享使用,放到redux中维护,比如token、个人信息
redux平替:zustand
Redux 核心
三大核心原则:单一数据源、状态只读、纯函数修改状态;
核心四要素:Store(仓库)、Action(描述行为)、Reducer(纯函数计算新状态)、Dispatch(派发动作);
单向数据流:dispatch→action→reducer→store→视图更新。
四、打包
1.打包
默认打包:npm run build
本地预览:npm i serve -g
serve -s ./build
2.vite
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build", // 生产打包
"build:test": "vite build --mode test", // 测试环境打包
}
}
//包体积分析(可视化看打包大小)
npm i vite-bundle-visualizer -D
import { defineConfig } from 'vite'
import { visualizer } from 'vite-bundle-visualizer'
export default defineConfig({
plugins: [visualizer()]
})
//执行打包自动打开分析页面
//打包
npm run build
//预览
npm run preview
3.webpack
{
"scripts": {
"dev": "webpack serve",
"build": "webpack --mode production"
}
}
//包体积分析(可视化看包大小)
npm i webpack-bundle-analyzer -D
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
plugins: [new BundleAnalyzerPlugin()]
}
//打包后自动弹出可视化图表,看各依赖占用体积。
//打包
npm run build
//预览
npx http-server dist
Webpack 全能适合传统应用项目;打包全量编译,插件生态完善,适配各类复杂项目;冷启动速度慢,适合大型复杂业务
Vite 开发体验强、新项目首选,打包底层基于 Rollup;按需编译,冷启动、热更新极快
Rollup 专注库打包,Tree-Shaking 最优、产物干净;
esbuild 编译速度极快,多用于预构建辅助加速。
编译速度:esbuild >> Vite (dev) > Webpack
打包产物纯净度:Rollup > Vite > Webpack
4.CDN 引入第三方库(减少打包体积)
非业务js放入cdn服务器,不参与打包
Webpack CDN 外部化 externals
module.exports = {
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
}
//public/index.html 手动引入 CDN:
<script src="https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js"></script>
5.路由懒加载
//router/index.js中
import { lazy, Suspense } from 'react'
//lazy动态导入
const Home = lazy(() => import('./pages/Home'))
const About = lazy(() => import('./pages/About'))
const Loading = () => <div>页面加载中...</div>
//包裹组件
<Suspense fallback={<Loading />}>
<Home />
</Suspense>
6.git
// 拉取远仓到本地(首次)
git clone 远程仓库地址
git add .
git commit -m "备注" 提交到本仓
//提交到远仓
git push
//查看提交记录
git log
五、底层
- React 基础理念
声明式编程、组件化开发、单向数据流、数据驱动视图、虚拟 DOM+Diff 算法,组合优于继承。
声明式:只描述页面最终状态,无需手动操作 DOM,框架自动完成视图更新;
组件化:页面拆分成独立可复用组件,降低维护成本;
单向数据流:数据自上而下通过 props 传递,数据变更可追溯;
数据驱动视图:状态改变自动更新页面,不用手动操作 DOM;
虚拟 DOM+Diff:用 JS 对象描述 DOM,差异化更新真实 DOM;
组合优于继承:使用组件组合、Hooks 复用逻辑,摒弃复杂类继承。
- 虚拟 DOM & Diff 算法
虚拟 DOM 是用纯 JS 对象映射真实 DOM 结构,规避频繁 DOM 操作带来的性能损耗。
为什么不直接操作 DOM?
真实 DOM 对象属性极多,创建、修改、查询开销大;频繁操作会持续触发回流重绘。
虚拟 DOM 会批量收集变更,通过 Diff 算出最小改动,一次性局部更新 DOM,减少页面重绘重排,性能更好。
Diff 算法用于新旧虚拟 DOM 对比,高效找出差异更新真实 DOM,遵循三条规则:
- 仅同层级节点比较,不跨层级移动 DOM;
- 节点标签不同,直接销毁旧节点重建新节点;
- 标签相同时对比属性、内容;列表渲染依靠 key 建立节点唯一映射,大幅提升对比效率。
React 与 Vue 的 diff 算法有何不同?
React Diff(简单双端遍历,无移动预判)
新旧列表首尾两端指针同时对比:头头、尾尾、头尾、尾头;
能复用的直接移动,无法匹配则标记为新增 / 删除;
没有计算最优移动方案,只会简单移动节点,乱序列表会产生多余 DOM 操作。
Vue3 Diff(最长递增子序列 LIS 优化)
先建立 key 与索引映射表,快速找到可复用节点;
找出不需要移动的稳定节点(最长递增子序列);
不在序列里的节点统一移动到末尾,最大化减少 DOM 移动操作;
乱序列表性能远优于 React。
-
触发组件重渲染
组件自身调用 setState、useState 更新、useReducer 的 dispatch 派发动作修改内部状态;
父组件重渲染,传递给子组件的 props 发生改变;
组件依赖的 Context 上下文 value 更新;
手动执行强制更新函数。
仅修改 ref、原地修改 state 不改变引用,不会触发重新渲染。 -
React 更新
React 更新分为 Render 渲染阶段和 Commit 执行阶段。Render 阶段可中断分片执行,只遍历 Fiber 树、执行 render 与 hooks、做 Diff 并标记 DOM 副作用,不操作真实 DOM;Commit 阶段不可中断,分三步同步执行 DOM 增删改、生命周期和 useLayoutEffect;页面真正渲染完成后才异步执行 useEffect。
React 渲染流程
初始化挂载:执行 render 生成虚拟 DOM,通过 Diff 生成真实 DOM 渲染到页面;
更新流程:state/props 发生变化,生成新虚拟 DOM,Diff 对比新旧树,仅将差异部分更新到真实 DOM。
- React 的 Fiber 架构
Fiber 是 React16 之后推出的全新调度架构,简单说就是把原来递归渲染的大任务,拆分成一个个很小的执行单元,它出现的原因是老版本的渲染是同步递归的,一旦任务量大就会阻塞主线程,导致页面卡顿、用户交互没响应。Fiber 可以在处理完一个小单元后,判断有没有用户输入、动画这类高优先级任务,如果有就暂停当前渲染,先处理高优先级任务,等空闲了再恢复。它能中断的核心改造是把虚拟 DOM 从树结构改成了链表结构,每个节点都记录父节点、子节点、兄弟节点,还能保存执行进度,所以可以随时暂停、恢复和继续执行。
React 事件机制
原理:底层通过事件委托将所有事件挂载到根容器,所有子组件事件统一由顶层捕获,减少 DOM 绑定数量;节省内存。
封装统一事件对象抹平浏览器差异,内置事件对象池复用优化内存;
合成事件内部 setState 会批量异步更新;异步中使用事件对象需要调用 e.persist ()。
顺序:触发->冒泡->合成->派发->回收
-
key 的作用
key 作为列表节点唯一标识,Diff 时快速匹配新旧节点,精准复用 DOM,减少删除重建操作。
不推荐用 index 下标做 key:数组增删、排序时下标错乱,会导致组件状态错乱、额外性能消耗。 -
高阶组件 HOC
高阶组件是接收组件、返回全新包装组件的函数,基于装饰器模式复用公共逻辑,常用于统一处理权限校验、页面 loading、埋点、请求封装。
装饰器模式:不修改原组件源码,通过包装一层实现功能叠加
// 装饰器:增加loading状态
function withLoading(Comp) {
return function Wrapper(props) {
if (props.loading) return <div>加载中...</div>
return <Comp {...props} />
}
}
// 原始组件,代码无改动
const Table = () => <div>表格数据</div>
// 装饰增强
const TableWithLoading = withLoading(Table)
-
React 严格模式
仅开发环境生效,用于代码检测:识别废弃生命周期 API、不安全副作用;会重复执行部分副作用,暴露定时器、订阅未销毁等内存泄漏问题。 -
react-intl
react-intl 是 React 官方国际化库,通过顶层IntlProvider注入语言包与语言标识;
组件内可用useIntl钩子在 JS 逻辑格式化文案,或<FormattedMessage>标签直接渲染;
支持动态插值、日期 / 数字货币格式化;
修改 locale 即可全局切换语言,大型项目配合defineMessages统一管理文案 ID
const [locale, setLocale] = useState('zh')
const messages = locale === 'zh' ? zh : en
return (
<IntlProvider locale={locale} messages={messages}>
<App setLocale={setLocale} />
</IntlProvider>
)
切换语言原理:locale 状态变更,IntlProvider 下发新 messages,子组件全部更新
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)