前端面试利器:React 核心知识点与 Anki 学习卡片

107 阅读28分钟

前端面试利器:React 核心知识点与 Anki 学习卡片

这是一套完整的 React 前端面试 Anki 卡片集,涵盖了 52 个核心面试主题,从基础原理到高级优化,从组件设计到架构模式,为你的 React 面试提供全方位支持。

📥 下载和使用

Anki 卡片集下载

本指南对应的 Anki 卡片集已发布到 AnkiWeb,你可以直接下载使用:

下载链接React 前端面试 Anki 卡片集

安装步骤

  1. 确保已安装 Anki 软件
  2. 打开 Anki,点击"工具" → "附加组件"
  3. 点击"获取附加组件",输入代码:1468498942
  4. 点击"确定"完成安装
  5. 重启 Anki 即可开始学习

卡片集特点

  • 📚 52 个核心主题:涵盖 React 面试的各个方面
  • 🎯 结构化内容:每个卡片包含回答思路、核心要点、面试模板
  • 📊 技术速查表:快速回顾关键概念和对比数据
  • 🔄 智能复习:基于遗忘曲线的科学复习安排
  • 📱 多平台支持:支持桌面版、移动版 Anki

使用建议

  • 建议每天学习 20-30 张卡片
  • 结合本文档进行深入学习
  • 定期回顾和总结学习成果
  • 结合实际项目进行实践

📚 目录概览

🎯 核心基础 (8 个主题)

⚡ 性能优化 (12 个主题)

🔧 状态管理 (8 个主题)

🎨 组件设计 (10 个主题)

🚀 高级特性 (8 个主题)

🏗️ 架构设计 (6 个主题)

🎯 核心基础

Context API 性能优化

问题:Context API 的性能注意事项有哪些?

核心策略

  1. 拆分 Context - 高频更新状态与低频状态分离,避免无关组件重渲染
  2. 稳定 Context 值 - useMemo 缓存值对象,useCallback 固定方法引用
  3. 组件渲染控制 - React.memo 防止 props 未变的子组件重渲染
  4. 精准消费粒度 - 只订阅必要数据(第三方库实现选择性消费)

面试表达模板

"Context 的核心性能问题是 Provider 的 value 变化会触发所有消费组件重渲,这在动态数据场景会导致性能瓶颈。

主要优化策略有四点:

  1. 拆分 Context:将高频更新数据和低频数据分离,避免无关组件被波及
  2. 稳定引用:用 useMemo 包裹 value 对象,useCallback 固定方法引用,避免无效重渲
  3. 组件缓存:消费组件用 React.memo 包裹,阻断父组件渲染的传导
  4. 精准订阅:通过 use-context-selector 等库实现细粒度消费"

技术原理速查表

策略错误示例正确实现性能影响
拆分Context所有状态塞进单个ContextUserContext + ConfigContext 分离减少 70%+ 重渲染组件
稳定值引用<Provider value={{data}}>const val = useMemo(()=>({data}),[data])避免 100% 无效重渲染
组件缓存直接消费组件export default memo(ConsumerComponent)阻断父更新传导
精准订阅useContext(WholeContext)useContextSelector(ctx, s=>s.value)重渲染范围缩小 90%+

Context 与 Props Drilling 的取舍

问题:Context 与 Props Drilling 的取舍?

选择 Context 的场景

  • 跨层级传递:当数据需穿透多层组件(≥3层)时,Context 避免逐层传递的冗余代码
  • 全局数据:主题、用户身份等跨组件共享的数据,Context 提供集中管理能力
  • 低频更新:如语言包、配置信息等更新频率低的数据,Context 性能可控

选择 Props Drilling 的场景

  • 层级较浅:数据仅传递1-2层时,Props 更简单直观,无额外心智负担
  • 数据隔离:需要强数据隔离的组件(如独立表单),Props 保证状态局部性
  • 可追溯性:Props 显式传递便于代码审查和数据流追踪,降低维护成本

决策原则

  • 层级深度优先:超过3层 → Context;3层以内 → Props Drilling
  • 数据变更频率:高频更新数据 → 慎用 Context,优先 Props + 状态提升
  • 团队共识:大型项目规范 → Context 需配套拆分/优化策略

React Diff 算法优化策略

问题:React Diff 算法的优化策略有哪些?

核心策略

  1. 同级比较 - 仅比较同层级节点,复杂度由 O(n³) 降至 O(n)
  2. Key 标识 - 唯一 key 追踪节点移动,最大化复用 DOM
  3. 类型重建 - 组件类型不同时直接重建子树,避免无效对比
  4. 增量更新 - Fiber 架构下支持可中断的渲染与分片更新

面试表达模板

"React Diff 通过层级限制(避免跨层遍历)和 Key追踪(节点复用)解决传统树对比的性能瓶颈,配合类型重建策略快速处理组件变更,最后利用 Fiber 的增量更新能力实现无阻塞渲染。"

性能提升效果

  • 列表渲染效率提升 3-5 倍
  • 动态节点更新快 60%+
  • 时间复杂度从 O(n³) 降至 O(n)

Fiber 架构并发渲染

问题:Fiber 架构如何实现可中断渲染?

核心实现原理

  1. 节点结构重构 - 将虚拟 DOM 节点升级为 Fiber 节点,包含组件类型、状态、副作用标记等完整信息
  2. 工作单元拆分 - 将渲染任务拆分为原子化工作单元(每个 Fiber 节点为一个单元)
  3. 双向链表遍历 - 子节点链路、兄弟节点链路、父节点链路形成深度优先遍历链路
  4. 时间切片调度 - 使用 requestIdleCallback 在浏览器空闲时段执行任务
  5. 中断恢复机制 - 进度暂存、优先级标记、断点续传
  6. 双缓存技术 - Current 树和 WorkInProgress 树

关键突破

  • 增量渲染:将连续任务拆解为可量化单元
  • 优先级调度:高优先级任务可抢占低优先级渲染
  • 无阻塞响应:维持主线程 60fps 流畅交互
  • 安全回退:未完成的渲染不会影响当前 UI

Fiber 架构解决的问题

问题:Fiber 架构解决了什么问题?

解决的核心问题

  1. 同步阻塞场景 - 长任务卡死主线程 → 可中断渲染+时间切片 → 拆分任务链分帧执行
  2. 交互延迟场景 - 用户操作被渲染阻塞 → 优先级调度 → 高优任务中断低优渲染
  3. 复杂更新场景 - 全量渲染效率低下 → 增量并发更新 → 仅计算变更部分
  4. 错误扩散场景 - 局部错误导致全局崩溃 → 错误边界隔离 → 组件树捕获异常

最终效果

  • 使 React 应用达到 60fps 流畅标准
  • 崩溃率降低 90%+
  • 交互响应速度 < 100ms

⚡ 性能优化

React.memo 优化原理和陷阱

问题:React.memo 的优化原理和陷阱?

优化原理

  • 浅比较策略:对函数组件的 props 进行浅层比较(引用比较),若 props 未变化则跳过渲染
  • 渲染拦截:当父组件重渲染时,被 React.memo 包裹的子组件仅在 props 变更时才执行渲染
  • 自定义比较:支持传入比较函数(第二参数)深度控制更新逻辑

主要陷阱

  1. 对象/数组陷阱 - 若传递新创建的对象/数组,浅比较因引用不同误判变更
  2. 函数引用陷阱 - 父组件传递内联函数,每次生成新函数引用触发子组件重渲染
  3. 浅比较盲区 - 嵌套对象属性变更无法被浅比较捕获
  4. 过度优化反作用 - 简单组件使用 React.memo 时,props 比较开销可能超过渲染本身
  5. 上下文变更无感知 - 子组件内部使用的 Context 变更时,React.memo 无法拦截

最佳实践

  • 适用场景:渲染开销大的组件,且 props 相对稳定
  • 规避陷阱:对象/数组 props 配合 useMemo,函数 props 配合 useCallback
  • 避免滥用:简单纯展示组件无需使用

React 性能优化三剑客

问题:React.memo、useMemo、useCallback 的区别和使用场景?

核心区别

  • React.memo - 缓存组件:Props 不变时阻止子组件重渲染
  • useMemo - 缓存计算结果:依赖不变时返回缓存值
  • useCallback - 缓存函数引用:依赖不变时保持函数地址不变

使用口诀

  • 子组件无效更新 → memo
  • 复杂计算重复执行 → useMemo
  • 回调引发子组件更新 → useCallback

实战场景速查表

问题现象解决方案代码示例性能提升
父组件更新导致子组件重渲React.memo 包裹子组件export default memo(StaticComponent)40-70%
列表过滤导致页面卡顿useMemo 缓存计算结果const list = useMemo(() => filter(items), [items])50%+
子组件因回调函数Prop重渲useCallback 固定函数引用const fn = useCallback(() => {}, [])30-60%

如何定位不必要的渲染

问题:如何定位不必要的渲染?

核心定位方法

  1. React DevTools 分析 - 使用 Profiler 组件记录渲染耗时,识别高代价渲染
  2. 性能监测工具 - 结合 Chrome DevTools 的 Performance 面板,分析组件生命周期耗时
  3. 渲染日志追踪 - 在组件内添加 console.log 或使用 useWhyDidYouUpdate Hook
  4. 严格模式检测 - 启用 <React.StrictMode> 暴露未预期副作用
  5. 记忆化校验 - 对 React.memo/useMemo/useCallback 包裹的组件,验证依赖项变更
  6. 状态更新溯源 - 检查 setState 调用点,确认是否因事件冒泡导致冗余更新

关键原则

  • 20/80 法则:优先优化渲染耗时 top 20% 的组件
  • 渐进式优化:避免过早优化,实测瓶颈后再干预
  • 工具组合:DevTools + 日志 + 性能面板三维定位

🔧 状态管理

Redux 三大原则

问题:Redux 三大原则是什么?

三大核心原则

  1. 单一数据源 - 整个应用状态存储在唯一一个 Store 对象树中,确保数据来源统一
  2. 状态只读 - 唯一改变状态的方式是 dispatch(action),禁止直接修改状态,保证变更可追踪
  3. 纯函数修改 - 通过 Reducer 纯函数处理状态变更,接收旧状态和 Action,返回全新状态对象(无副作用)

核心价值

  • 可预测性:状态变更由 Action 严格描述,Reducer 纯函数保证输出确定性
  • 可维护性:单向数据流(View → Action → Reducer → Store → View)结构清晰
  • 调试能力:单一 Store + 纯函数支持时间旅行调试(Time Travel)

Redux Toolkit 痛点解决

问题:Redux Toolkit 解决了哪些痛点?

解决的痛点

  1. 简化配置 - 内置 configureStore 自动集成 Redux DevTools 和中间件
  2. 减少样板代码 - createSlice 自动生成 action types 和 creators
  3. 不可变更新优化 - 整合 Immer 库,允许在 reducer 中直接修改状态草稿
  4. 内置异步处理 - 提供 createAsyncThunk 简化异步请求管理
  5. 模块化组织 - 支持按功能拆分 slices,便于代码维护和状态隔离
  6. 包体积优化 - 减少冗余工具库依赖,降低最终打包体积
  7. 类型安全 - 原生支持 TypeScript 类型推导

核心价值

  • 开发效率提升 3X+
  • 减少 60% 以上冗余代码
  • 保持 Redux 核心原则(单向数据流/可预测性)

Zustand 基本用法总结

问题:Zustand 基本用法总结?

核心用法

  1. 创建 Store - const useStore = create((set) => ({...}))
  2. 定义状态 - 在 create 回调中声明初始状态变量
  3. 添加动作 - 在 store 中创建更新状态的方法
  4. 组件使用 - const state = useStore() 获取完整状态
  5. 选择状态 - const value = useStore(state => state.key) 订阅部分状态
  6. 更新状态 - 在动作中调用 set({ key: newValue })
  7. 异步操作 - 直接在动作中处理异步逻辑后调用 set
  8. 持久化存储 - 添加 persist 中间件保存到 localStorage
  9. 开发者工具 - 应用 devtools 中间件启用调试
  10. 类型安全 - 使用 TypeScript 接口定义状态类型

优势

  • 轻量级:包体积小,API 简洁
  • 灵活:支持多种状态管理模式
  • 性能:精确订阅,避免不必要的重渲染
  • 易用:学习成本低,上手快

🎨 组件设计

React Hooks 革命性特性

问题:React Hooks:函数组件的革命性特性?

四大核心革命性突破

  1. 状态与生命周期赋能 - useState/useEffect 使函数组件具备类组件能力,消除 this 绑定痛点
  2. 逻辑复用范式革新 - 自定义Hook取代HOC/render props,根治"wrapper hell"嵌套地狱
  3. 代码组织逻辑聚合 - 相关逻辑集中书写(如数据获取+状态更新),告别生命周期碎片化
  4. 未来特性无缝适配 - 原生支持并发模式(useTransition)、SSR(useId)等新特性

技术对比表(类组件 vs Hooks)

能力类组件Hooks突破点
状态管理this.state + setStateuseState + useReducer消除 this 绑定烦恼
副作用控制分散在多个生命周期方法useEffect 统一处理关联逻辑聚合
逻辑复用HOC嵌套导致wrapper hell自定义Hook(如 useAuth)实现扁平化复用
代码量平均多40%模板代码极致简洁开发效率提升35%+
未来兼容性难以适配并发模式原生支持 useTransition等新特性面向未来架构

受控组件 vs 非受控组件

问题:受控组件 vs 非受控组件?

核心区别

  1. 数据控制权 - 受控组件由 React 状态管理数据,非受控组件由 DOM 自身管理数据
  2. 数据更新 - 受控组件通过 onChange 事件同步状态,非受控组件通过 ref 获取 DOM 值
  3. 实时性 - 受控组件实时更新状态,非受控组件在提交时(如表单提交)才获取值
  4. 使用场景 - 受控组件适用于复杂表单交互,非受控组件适用于简单表单或第三方库集成
  5. 推荐程度 - React 官方推荐受控组件,因其更符合 React 数据流思想
  6. 代码复杂度 - 受控组件需编写状态处理逻辑,非受控组件代码更简洁但可控性低

使用场景对比

场景推荐方案原因示例
复杂表单交互受控组件实时验证和状态管理用户注册表单
简单表单非受控组件代码简洁搜索框
第三方库集成非受控组件避免冲突富文本编辑器
表单验证受控组件实时验证登录表单
文件上传非受控组件文件对象处理图片上传
动态表单受控组件状态管理动态添加字段

类组件 vs 函数组件的区别

问题:类组件 vs 函数组件的区别?

核心区别

  1. 声明方式 - 类组件使用 ES6 class 继承 React.Component,函数组件是普通 JavaScript 函数
  2. 状态管理 - 类组件通过 this.state/setState 管理状态;函数组件使用 useState Hook
  3. 生命周期 - 类组件有明确生命周期方法(如 componentDidMount);函数组件用 useEffect 统一处理副作用
  4. 逻辑复用 - 类组件通过 HOC 或 Render Props 复用逻辑;函数组件通过自定义 Hooks 实现
  5. 代码组织 - 类组件逻辑分散在生命周期方法中;函数组件用 Hooks 聚合相关逻辑
  6. 性能优化 - 类组件用 shouldComponentUpdate/PureComponent;函数组件用 React.memo/useMemo
  7. 设计哲学 - 类组件面向对象;函数组件函数式编程 + 组合
  8. 趋势 - 函数组件 + Hooks 为现代 React 开发主流模式

使用场景对比

场景推荐方案原因示例
新项目开发函数组件现代 React 开发主流所有新项目
状态管理复杂函数组件Hooks 聚合逻辑复杂状态逻辑
逻辑复用需求函数组件自定义 Hooks通用逻辑封装
性能优化函数组件更精细的优化控制性能敏感场景
代码可读性函数组件逻辑聚合,更清晰复杂组件
测试友好函数组件纯函数,易测试单元测试

🚀 高级特性

React 18+ Concurrent 模式

问题:React 18+ Concurrent 模式解决了什么问题?

解决的核心问题

  1. 渲染阻塞问题 - 传统同步渲染一旦开始便不可中断,长任务阻塞主线程导致交互卡顿
  2. 优先级调度缺失 - 所有更新平等竞争资源,高优先级操作需等待低优先级任务完成
  3. 渲染浪费 - 快速连续更新触发多次完整渲染,但仅需应用最终状态
  4. 加载体验割裂 - 数据/代码加载时组件突然弹出内容,缺乏平滑过渡

解决方案核心

  1. 可中断渲染 - 将渲染工作拆分为微小单元,高优先级任务可中断低优先级渲染
  2. 优先级调度 - 紧急更新立即执行,过渡更新通过 startTransition 标记延后
  3. 并行渲染 - 后台静默准备新 UI 版本,就绪后无缝切换
  4. 批处理更新机制 - 将多次 DOM 差异合并为单次更新

实际场景受益

场景传统模式痛点Concurrent 解决方案
输入框搜索输入卡顿,渲染阻塞键盘响应中断渲染优先处理输入事件
页面跳转点击后延迟等待新内容加载后台预渲染新路由 + Suspense 过渡
大列表过滤过滤计算冻结界面useDeferredValue 延后非紧急更新
复杂面板更新整体渲染导致动画掉帧增量渲染维持 60fps 流畅度

startTransition 和 useDeferredValue 区别

问题:startTransition 和 useDeferredValue 区别?

核心区别

  1. 设计目的 - startTransition:主动标记状态更新为低优先级;useDeferredValue:被动生成状态的延迟副本
  2. 触发方式 - startTransition:开发者手动包裹状态更新函数;useDeferredValue:组件内自动响应状态变化
  3. 更新行为 - startTransition:原始状态立即生效,被包裹的更新延迟执行;useDeferredValue:原始状态立即渲染,派生值后台计算后更新
  4. 适用场景 - startTransition:控制更新源头(如用户输入触发的搜索请求);useDeferredValue:优化消费端(如复杂计算结果的渲染降级)
  5. 性能影响 - startTransition:减少高优先级任务阻塞;useDeferredValue:避免派生状态引发的渲染卡顿

本质区别

  • startTransition → 更新优先级调度器(主动控制任务队列)
  • useDeferredValue → 状态缓冲代理(自动维护值的最新/延迟双版本)

为什么 Hooks 不能条件调用

问题:为什么 Hooks 不能条件调用?

核心原因

  1. 链表顺序强依赖 - Hooks 依赖底层单向链表结构存储状态,每个 Hook 节点按声明顺序严格排列
  2. Fiber 节点状态映射 - 组件更新时,React 通过固定顺序从 Fiber 节点的 memoizedState 链表读取状态
  3. 渲染稳定性要求 - React 使用当前指针按序遍历 Hook 节点,条件跳过 Hook 会导致指针偏移
  4. 热更新兼容风险 - 开发环境下组件热重载时,条件调用可能造成新旧链表节点错位
  5. 服务端渲染约束 - SSR 中组件渲染序列必须与客户端完全一致

设计本质: Hooks 的链表机制以声明顺序为唯一状态标识(类似数组索引),其稳定性是函数组件状态管理的基石。条件调用相当于在运行时动态改变数组长度,必然导致数据引用错乱。

解决方案

  • 条件数据:在 Hook 内部实现条件逻辑
  • 条件副作用:在 useEffect 依赖项中控制

自定义 Hook 测试策略

问题:如何测试自定义 Hook?

核心测试方法

  1. renderHook 核心工具 - 使用 @testing-library/react 的 renderHook 方法,无需创建测试组件
  2. 异步操作处理 - 结合 waitFor 和 act 处理异步逻辑,确保状态更新完成后再进行断言
  3. 上下文依赖模拟 - 通过 wrapper 参数注入 Provider,模拟 Hook 所需的 Context 环境
  4. 参数动态测试 - 使用 rerender 方法更新 Hook 参数,验证不同输入下的行为变化
  5. 副作用验证 - 用 Jest 模拟函数追踪 Hook 内调用的外部方法
  6. 边界条件覆盖 - 测试初始状态、空值、异常输入等边界场景
  7. 内存泄漏检测 - 验证 useEffect 清理函数是否正常执行
  8. 类型辅助 - 配合 TypeScript 类型断言,确保返回值和方法的类型正确性

测试示例

// 基础功能测试
const { result } = renderHook(() => useCounter())

// 异步操作测试
await waitFor(() => expect(result.current.data).toBeDefined())

// 上下文依赖测试
renderHook(() => useAuth(), { wrapper: AuthProvider })

// 参数变化测试
rerender({ initialValue: 10 })

// 副作用验证
const spy = jest.spyOn(api, 'fetchData')

🏗️ 架构设计

如何组织大型 React 项目结构

问题:如何组织大型 React 项目结构?

核心组织原则

  1. 领域驱动分层 - 按业务模块划分目录(如 user/, order/),每个模块包含组件/逻辑/API 等完整闭环
  2. 原子化组件分类 - 组件库分层为 ui/(基础组件)、features/(业务组件)、layouts/(页面框架)
  3. 集中状态管理 - 状态层独立为 store/ 目录,按模块拆分 slices(Redux)或 contexts(Context API)
  4. 服务层抽象 - 将 API 请求、工具函数放入 services/ 和 utils/,实现业务逻辑与 UI 解耦
  5. 路由统一管理 - 路由配置集中到 routes/ 目录,支持动态导入和权限控制
  6. 定制 Hook 封装 - 复用逻辑抽离为 hooks/,如 useAuth、usePagination
  7. 静态资源分区 - 样式/字体/图片等按类型归入 assets/,全局样式通过主题提供
  8. 环境配置隔离 - 配置文件(常量/环境变量)放入 config/,区分开发与生产环境
  9. 测试同源定位 - 测试文件与源码同级存放(如 Component.tsx + Component.test.tsx)

项目结构示例

src/
├── modules/          # 业务模块
│   ├── cart/         # 购物车领域
│   │   ├── components/
│   │   ├── hooks/
│   │   └── store/
├── core/             # 核心层
│   ├── store/        # 全局状态管理
│   ├── router/       # 路由配置
│    └── api/          # 网络请求封装
├── shared/           # 共享资源
│   ├── ui/           # 通用组件库
│    └── utils/        # 工具函数
├── assets/           # 静态资源
└── App.tsx           # 应用入口

核心原则

  • 高内聚:关联文件就近组织(如组件+样式+hook 同目录)
  • 低耦合:模块间通过接口通信,禁止跨模块直接引用
  • 渐进扩展:初期保持扁平,随规模增长逐步分层

组件库设计原则

问题:组件库设计原则?

核心设计原则

  1. 原子化设计 - 遵循原子设计方法论(原子 → 分子 → 组织 → 模板),建立清晰的组件层级关系
  2. API 一致性 - 统一组件命名规范(如 Button/ButtonGroup)和属性模式(如 value/onChange)
  3. 无障碍优先 - 内置 ARIA 属性和键盘导航支持,确保 WCAG 2.1 合规性
  4. 主题化定制 - 通过 CSS 变量或 ThemeProvider 实现样式解耦,支持动态换肤
  5. 类型安全 - 使用 TypeScript 定义完整 Props 类型,提供自动补全和文档提示
  6. 文档驱动 - 集成 Storybook 或 Docusaurus 提供交互式文档和可视化用例
  7. 版本控制 - 严格遵循语义化版本(SemVer),重大变更通过 Major 版本升级
  8. 按需加载 - 支持 Tree Shaking 和模块化导出,避免全量引入的冗余体积
  9. 测试覆盖 - 单元测试(Jest) + 交互测试(React Testing Library) + 视觉回归测试(Chromatic)
  10. 国际化扩展 - 内置 i18n 多语言支持,预留本地化扩展接口

黄金法则

  1. 克制性原则 - 不做过度封装,保持组件功能单一性
  2. 逆向兼容 - 非破坏性变更需向下兼容,废弃 API 提供迁移路径
  3. 场景驱动 - 基于真实业务用例设计而非抽象理论

🛠️ 实用工具

实现 usePrevious Hook

问题:实现 usePrevious Hook?

核心实现

import { useRef, useEffect } from 'react';

function usePrevious(value) {
  const ref = useRef();
  
  useEffect(() => {
    ref.current = value; // 渲染完成后更新为当前值
  }, [value]); // 依赖变化时触发
  
  return ref.current; // 返回的是上一次渲染时的值
}

核心原理

  1. useRef 持久化存储 - useRef 创建的对象在组件生命周期内保持不变,其 .current 属性可存储任意值且变更不会触发重渲染
  2. useEffect 滞后更新 - 在渲染提交到屏幕后更新 ref 的值,确保返回的是前次渲染的状态
  3. 依赖驱动更新 - 当 value 变化时,useEffect 在下次渲染后更新 ref.current

使用示例

function Component() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  // 首次渲染: count=0, prevCount=undefined
  // 点击后渲染: count=1, prevCount=0
  
  return (
    <button onClick={() => setCount(c => c + 1)}>
      Now: {count}, Before: {prevCount ?? "null"}
    </button>
  );
}

适用场景

  • 动画效果:比较前后值变化
  • 数据变化检测:监控状态变化
  • 性能优化:避免不必要的计算
  • 调试:追踪值的变化历史

封装 useFetch 数据请求 Hook

问题:封装 useFetch 数据请求 Hook?

核心实现

import { useState, useEffect } from 'react';

function useFetch(url, options = {}) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const abortController = new AbortController();
    
    const fetchData = async () => {
      try {
        setLoading(true);
        const response = await fetch(url, {
          ...options,
          signal: abortController.signal
        });
        
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const json = await response.json();
        setData(json);
        setError(null);
      } catch (err) {
        if (err.name !== 'AbortError') {
          setError(err.message || '请求失败');
        }
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => abortController.abort();
  }, [url, JSON.stringify(options)]);

  return { data, loading, error };
}

核心特性

  1. 三态管理 - loading:请求进行中;data:成功响应数据;error:失败错误信息
  2. 自动取消机制 - 使用 AbortController 在组件卸载或重新请求时取消前次请求
  3. 依赖驱动更新 - 当 URL 或 options 变化时自动重新请求
  4. 错误处理 - 统一处理网络错误和异常状态,区分 AbortError 和其他错误

使用示例

function UserProfile({ userId }) {
  const { data, loading, error } = useFetch(
    `https://api.example.com/users/${userId}`,
    { headers: { Authorization: 'Bearer token' } }
  );

  if (loading) return <Spinner />;
  if (error) return <Error message={error} />;
  
  return <ProfileCard user={data} />;
}

扩展建议

  • 添加缓存层:结合 useRef 实现简单缓存
  • 重试机制:增加 retryCount 参数
  • 轮询支持:添加 interval 参数实现定时刷新
  • 分页集成:返回 fetchNextPage 方法支持分页加载

📊 学习建议

学习路径

  1. 基础阶段:掌握 React 核心概念和 Hooks 基础用法
  2. 进阶阶段:深入理解性能优化和状态管理
  3. 高级阶段:学习架构设计和高级特性
  4. 实战阶段:结合实际项目应用所学知识

面试准备

  1. 理论掌握:理解每个概念的核心原理和实现机制
  2. 实践应用:能够结合实际场景选择合适的解决方案
  3. 表达训练:使用提供的面试表达模板进行练习
  4. 追问准备:熟悉高频追问的应对策略

持续学习

  1. 关注更新:跟踪 React 官方最新特性和最佳实践
  2. 社区参与:参与技术社区讨论,分享经验
  3. 项目实践:在实际项目中应用和验证所学知识
  4. 技术分享:通过技术分享加深理解

🎯 总结

这套 React 前端面试 Anki 卡片集涵盖了 52 个核心主题,从基础原理到高级优化,从组件设计到架构模式,为你的 React 面试提供全方位支持。

每个主题都包含:

  • 回答思路:清晰的逻辑框架
  • 核心内容:详细的技术要点
  • 面试表达模板:结构化的表达方式
  • 技术原理速查表:快速回顾核心概念
  • 高频追问应对预案:常见问题的标准回答

通过系统学习这些内容,你将能够:

  • 深入理解 React 的核心原理和设计思想
  • 掌握性能优化的各种策略和技巧
  • 学会选择合适的架构模式和设计原则
  • 在面试中自信、系统地回答问题
  • 在实际项目中应用最佳实践

记住,技术学习是一个持续的过程,保持好奇心,不断实践,你一定能成为优秀的 React 开发者!

🎴 Anki 使用指南

为什么选择 Anki?

Anki 是一款基于科学记忆原理的间隔重复学习软件,特别适合技术面试准备:

核心优势

  • 🧠 科学记忆:基于遗忘曲线,在最佳时机复习
  • 高效学习:避免重复学习已掌握的内容
  • 📱 随时随地:支持多平台同步,碎片时间学习
  • 📊 进度跟踪:清晰的学习统计和进度管理
  • 🔄 长期记忆:将短期记忆转化为长期记忆

学习策略建议

1. 分阶段学习

第一阶段(1-2周):基础概念
- 每天 15-20 张卡片
- 重点掌握核心原理和基础概念
- 结合本文档深入学习

第二阶段(2-3周):进阶应用
- 每天 20-25 张卡片
- 重点学习性能优化和状态管理
- 开始结合实际项目思考

第三阶段(1-2周):高级特性
- 每天 25-30 张卡片
- 重点掌握架构设计和高级特性
- 准备面试表达和追问应对

2. 学习技巧

  • 主动回忆:看到问题先自己思考,再看答案
  • 关联记忆:将新知识与已有知识建立联系
  • 实践结合:每学一个概念,尝试在项目中应用
  • 定期总结:每周总结学习成果,查漏补缺

3. 复习策略

  • 新卡片:每天学习新卡片,不要贪多
  • 复习卡片:按照 Anki 的复习计划进行
  • 困难卡片:标记困难卡片,重点复习
  • 暂停学习:遇到困难时不要暂停,保持学习节奏

面试准备流程

准备阶段(1-2个月)

  1. 理论学习:使用 Anki 卡片学习基础概念
  2. 深度理解:结合本文档深入理解每个概念
  3. 实践应用:在项目中应用所学知识
  4. 模拟面试:找朋友或同事进行模拟面试

冲刺阶段(1-2周)

  1. 重点复习:重点复习标记的困难卡片
  2. 表达训练:使用面试表达模板进行练习
  3. 追问准备:熟悉高频追问的应对策略
  4. 项目整理:整理项目经验,准备具体案例

常见问题解答

Q: 每天学习多少张卡片合适? A: 建议每天 20-30 张卡片,包括新卡片和复习卡片。具体数量可以根据个人时间安排调整。

Q: 遇到困难的概念怎么办? A: 可以标记为困难卡片,结合本文档深入学习,或者暂停该卡片,先学习其他相关内容。

Q: 如何保持学习动力? A: 设定明确的学习目标,定期回顾学习成果,结合实际项目进行实践,与朋友分享学习心得。

Q: 学习多久能看到效果? A: 一般坚持学习 2-4 周就能看到明显效果,但建议长期坚持,形成稳定的学习习惯。

技术支持

如果在使用 Anki 卡片集过程中遇到问题,可以:

  1. 查看 Anki 官方文档Anki 用户手册
  2. 参考本文档:结合详细的技术说明进行学习
  3. 社区求助:在技术社区寻求帮助
  4. 实践验证:通过实际项目验证所学知识

本文档基于 React 18+ 版本编写,涵盖了最新的特性和最佳实践。建议结合实际项目进行学习和实践。

Anki 卡片集下载React 前端面试 Anki 卡片集