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 多行时可用括号包起来(标签)

4.{} 识别 JavaScript中的表达式( 字符串、javaScript变量 、函数调用、JavaScript对象)

5.条件渲染:

  • 逻辑与
  • 三元
  • 自定义函数 + if判断语句

5.事件绑定

on 事件名称 = { 事件处理程序 },遵循驼峰命名法

传出数据用箭头函数

6.组件

一个组件就是首字母大写的函数

7.useState() 渲染、修改、收集、记录数据时使用

向组件添加一个状态变量, 从而控制影响组件的渲染结果

不能直接修改原数据

8.样式控制

  • 类名
  • 动态控制类名 ('静态类名',{动态类名:条件})

    9.受控表单绑定(数据由state管理)


    10.获取DOM(数据由dom管理)在渲染后

    11.组件通信
  • 父传子:在子组件标签上绑定属性 ,子组件通过props参数接收数据,props是只读对象,props.children表示子标签的内容
  • 子传父:父声明含参函数,子标签绑定;子组件中传递解构参数,调用父组件中的箭头函数并传递数据实参
  • 兄弟通信:状态提升(先子传父后父传子)
  • 跨层通信:

1.使用createContext方法创建一个上下文对象Ctx

  1. 在顶层组件(App)中通过 Ctx.Provider 组件提供数据value (标签)

  2. 在底层组件(B)中通过 useContext(Ctx) 钩子函数获取 数据

  3. value更新,所有消费组件都重渲染

12.useEffect

组件渲染完毕之后就需要和服务器要数据,整个过程属于"只由渲染引起的操作",渲染后执行

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

13.自定义Hook函数

use命名, 返回仍需使用的状态、方法。

可以通过解构来使用。

只能在组件顶层或者其他自定义Hook函数中调用。

14.接口获取数据

  • 定义接口文件 放数据
  • 定义命令
  • 请求数据并渲染
    useEffect(()=>{async function- (){await axios.get(''),set-() }, -()}, )

15.封装和复用

子:封装负责渲染的组件 UI组件

父:当作标签使用

过程涉及通信

状态上提,视图下沉(上层管理状态,下层纯UI复用)

16.优化

useMemo:缓存计算结果

js 复制代码
//只在依赖数组发生变化时,才重新执行函数计算新值;依赖不变直接复用缓存值。
const cachedValue = useMemo(() => {
  // 纯计算逻辑
  return 计算结果
}, [依赖1, 依赖2])

useCallback:缓存函数本身

js 复制代码
const handleClick = useCallback(() => {}, [])

17.常用

删除页面数据时,可以使用_.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 中导入组件并配置
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
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.二级路由

先创建组件,再配置

js 复制代码
//在配置中写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.跳转

js 复制代码
//跳转链接
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

三、redux

1.安装 npm install @reduxjs/toolkit react-redux

2.编写子模块

store/module/userSlice.js

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

js 复制代码
import { configureStore } from '@reduxjs/toolkit'
import userReducer from './slice/userSlice'

export const store = configureStore({
  reducer: {
    user: userReducer
  }
})

4.注入store

js 复制代码
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

js 复制代码
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、个人信息

四、优化

1.打包

默认打包:npm run build

本地预览:npm i serve -g

serve -s ./build

2.vite

js 复制代码
{
  "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

js 复制代码
{
  "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

4.CDN 引入第三方库(减少打包体积)

非业务js放入cdn服务器,不参与打包

Webpack CDN 外部化 externals

js 复制代码
module.exports = {
  externals: {
    'react': 'React',
    'react-dom': 'ReactDOM'
  }
}
html 复制代码
//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.路由懒加载

js 复制代码
//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

js 复制代码
// 拉取远仓到本地(首次)
git clone 远程仓库地址

git add . 
git commit -m "备注" 提交到本仓
//提交到远仓
git push 
//查看提交记录
git log
  1. 性能优化

资源优化:静态资源压缩、图片懒加载、CDN 分发、合理使用浏览器缓存;

渲染优化:减少回流重绘、长列表虚拟滚动、动画使用 transform 硬件加速;

请求优化:接口防抖节流、接口缓存、合并请求;

打包优化:代码分包、路由组件懒加载、第三方依赖 CDN 外置、Tree-Shaking 剔除无用代码;

React 渲染优化:memo、useMemo、useCallback 减少无效重渲染。

五、React 高频

  1. React 基础理念
    声明式编程、组件化开发、单向数据流、数据驱动视图、虚拟 DOM+Diff 算法,组合优于继承。
    声明式:只描述页面最终状态,无需手动操作 DOM,框架自动完成视图更新;
    组件化:页面拆分成独立可复用组件,降低维护成本;
    单向数据流:数据自上而下通过 props 传递,数据变更可追溯;
    数据驱动视图:状态改变自动更新页面,不用手动操作 DOM;
    虚拟 DOM+Diff:用 JS 对象描述 DOM,差异化更新真实 DOM;
    组合优于继承:使用组件组合、Hooks 复用逻辑,摒弃复杂类继承。
  2. 虚拟 DOM & Diff 算法
    虚拟 DOM 是用纯 JS 对象映射真实 DOM 结构,脱离浏览器 API,规避频繁 DOM 操作带来的性能损耗。
    Diff 算法用于新旧虚拟 DOM 对比,高效找出差异更新真实 DOM,遵循三条规则:
  • 仅同层级节点比较,不跨层级移动 DOM;
  • 节点标签不同,直接销毁旧节点重建新节点;
  • 标签相同时对比属性、内容;列表渲染依靠 key 建立节点唯一映射,大幅提升对比效率。
  1. key 的作用
    key 作为列表节点唯一标识,Diff 时快速匹配新旧节点,精准复用 DOM,减少删除重建操作。
    不推荐用 index 下标做 key:数组增删、排序时下标错乱,会导致组件状态错乱、额外性能消耗。
  2. 为什么不直接操作 DOM
    真实 DOM 对象属性极多,创建、修改、查询开销大;频繁操作会持续触发回流重绘。
    虚拟 DOM 会批量收集变更,通过 Diff 算出最小改动,一次性局部更新 DOM,减少页面重绘重排,性能更好。
  3. 组件通信方式
    父子组件:父传子 props,子传父回调函数;
    兄弟组件:状态提升至共同父组件、Context、全局状态库;
    跨多层级组件:Context、Redux/Zustand 等状态管理;
    任意无关联组件:全局事件订阅、全局状态。
  4. hooks 规则
    仅能在函数组件或自定义 Hook 内部调用;
    禁止在循环、条件判断、嵌套函数中使用;
    保证每次渲染 Hook 调用顺序固定,依赖校验正常工作。
  5. useState /useEffect 用法
    useState:管理组件局部状态,setState 更新是异步批量合并,多次更新会合并执行。
    useEffect:统一处理所有副作用,如接口请求、定时器、事件订阅、DOM 操作;通过依赖数组控制执行时机;
    注意:useEffect 回调不能直接加 async,需在内部单独定义异步函数执行。
  6. useRef 作用
  • 获取真实 DOM 元素实例;
  • 保存跨渲染周期不变的数据、定时器 ID;
  • 存储组件实例变量,修改不会触发组件重渲染。
  1. useMemo /useCallback 区别
    二者均为性能优化 Hook,都依赖依赖数组控制更新:
    useMemo:缓存函数计算后的结果,避免每次渲染重复执行昂贵计算;
    useCallback:缓存函数引用,防止函数地址频繁变化,配合 memo 避免子组件无效重渲染。
  2. 受控组件、非受控组件
    受控组件:表单 value 绑定组件 state,表单值完全由 React 状态管控,变更通过 onChange 同步;
    非受控组件:不绑定 state,通过 useRef 获取 DOM 原生 value,表单数据由 DOM 自身维护。
  3. 高阶组件 HOC
    高阶组件是接收组件、返回全新包装组件的函数,基于装饰器模式复用公共逻辑,常用于统一处理权限校验、页面 loading、埋点、请求封装。
  4. Context 作用
    实现跨层级组件数据透传,避免多层组件逐层传递 props 的 "props drilling" 问题,适合全局主题、用户信息、配置等全局数据。
  5. React 严格模式
    仅开发环境生效,用于代码检测:识别废弃生命周期 API、不安全副作用;会重复执行部分副作用,暴露定时器、订阅未销毁等内存泄漏问题。
  6. props.children 和 React.Children
    props.children 是组件插槽传入的子元素,类型不固定(文本、数组、组件、undefined 都有可能);
    React.Children 是内置工具集,提供 map/forEach 等安全遍历方法,兼容所有 children 类型,避免类型报错。
  7. React 为什么要用 JSX
    JSX 是 React.createElement 的语法糖,把 HTML 结构写进 JS 代码;实现 UI 与业务逻辑内聚,拥有完整 JS 语法能力,符合声明式开发,可读性更强。
  8. 状态提升
    当多个兄弟组件需要共享同一份数据时,将共享状态提升到它们最近的共同父组件统一管理,通过 props 分发给子组件,实现兄弟通信。
  9. React 渲染流程
    初始化挂载:执行 render 生成虚拟 DOM,通过 Diff 生成真实 DOM 渲染到页面;
    更新流程:state/props 发生变化,生成新虚拟 DOM,Diff 对比新旧树,仅将差异部分更新到真实 DOM。
  10. Redux 核心
    三大核心原则:单一数据源、状态只读、纯函数修改状态;
    核心四要素:Store(仓库)、Action(描述行为)、Reducer(纯函数计算新状态)、Dispatch(派发动作);
    单向数据流:dispatch→action→reducer→store→视图更新。
  11. 打包工具区别
    Webpack:打包全量编译,插件生态完善,适配各类复杂项目;冷启动速度慢,适合大型复杂业务;
    Vite:基于 ESModule 原生模块,开发环境预构建第三方依赖,按需编译,冷启动、热更新极快;打包底层基于 Rollup,新项目主流选择。
相关推荐
FirstFrost --sy1 小时前
基于高并发服务器的web小游戏测试
服务器·前端·javascript·c++·python·集成测试
youyu-youyu1 小时前
oss阿里云图片链接url高清图片设置为缩略图 vue 减少加载体积流量
前端·javascript·vue.js·阿里云·云计算
独隅1 小时前
前端工程化在Chrome插件开发中的具体实践完全指南
前端·chrome
sbjdhjd1 小时前
Tomcat(下) 集群高可用实战:反向代理・负载均衡・分布式 Session
运维·前端·云原生·开源·tomcat·负载均衡·memcached
低保和光头哪个先来1 小时前
聊聊 CSS 编译和 scoped 实现
前端·css·vue.js
object not found1 小时前
Node.js fs 常用 API 整理:node:fs/promises、node:fs、fs 到底怎么用
开发语言·前端·javascript
LiuJun2Son2 小时前
Angular 快速入门:服务和依赖注入
前端·javascript·angular.js
kidding7232 小时前
BMI 健康测量仪工具类小程序
前端·微信小程序·小程序
KaMeidebaby2 小时前
卡梅德生物技术快报|兔单克隆抗体应用实战:禽源病原 IFA 检测全流程拆解
前端·人工智能·物联网·算法·百度