diff --git a/react/README.md b/react/README.md
new file mode 100644
index 0000000..ba00c1b
--- /dev/null
+++ b/react/README.md
@@ -0,0 +1,236 @@
+# React 深度面试题及解析 (Vue 3 开发者视角版)
+
+> 本文档专为熟悉 Vue 3 + TypeScript 的开发者编写。我们将通过对比 Vue 3 的核心概念(响应式、Composition API、Diff 算法等)来深度解析 React 的原理,帮助你快速建立映射关系并掌握 React 高频面试点。
+
+---
+
+## 目录
+
+1. [核心设计理念对比](#1-核心设计理念对比)
+2. [Hooks 与 Composition API](#2-hooks-与-composition-api)
+3. [Fiber 架构与并发模式](#3-fiber-架构与并发模式)
+4. [状态管理与组件通信](#4-状态管理与组件通信)
+5. [性能优化机制](#5-性能优化机制)
+6. [Diff 算法深度解析](#6-diff-算法深度解析)
+7. [TypeScript 实战差异](#7-typescript-实战差异)
+
+---
+
+## 1. 核心设计理念对比
+
+### Q1: React 的"不可变数据" (Immutable) 与 Vue 的"可变响应式" (Mutable) 有什么本质区别?为什么 React 需要它?
+
+**Vue 3 视角解析:**
+在 Vue 3 中,我们习惯直接修改对象 `state.count++`,Proxy 会拦截这个操作并自动触发更新。这是 **"Mutable + 细粒度依赖收集"**。
+
+**React 原理:**
+React 是 **"Immutable + 全量检测"**(组件级)。
+- **不可变性**:React 中不能直接修改 state (`this.state.count++` 是无效的),必须调用 `setState` 传入一个新的值。
+- **为什么**:React 没有细粒度的依赖收集系统。当状态变化时,React 默认不知道具体哪个属性变了,它只知道"组件需要更新了"。通过比较 `oldState === newState` (浅比较) 来决定是否需要重新渲染。如果数据是可变的,引用没变但内容变了,React 就无法快速感知变化,或者需要昂贵的深比较。
+
+**面试回答要点:**
+1. **数据流向**:React 强调单向数据流和不可变性,通过 `setState` 触发更新,生成全新的 Virtual DOM 树。
+2. **更新策略**:Vue 是"推"(Push)模式,依赖变了自动推送到组件;React 是"拉"(Pull)模式,状态变了,React 重新执行组件函数,产出新 UI。
+3. **心智模型**:React 组件本质是 `UI = f(state)`,每次 Render 都是一次全新的函数调用,闭包在其中扮演核心角色(Capture Value 特性)。
+
+---
+
+### Q2: JSX 与 Vue Template 的编译结果有什么不同?
+
+**Vue 3 视角解析:**
+Vue Template 编译成 Render Function,但 Vue 做了大量**编译时优化**(PatchFlags、静态提升、Block Tree),能静态分析出哪些节点是动态的。
+
+**React 原理:**
+JSX 本质是 `React.createElement` (或 `_jsx`) 的语法糖。
+- **灵活性**:JSX 是完全的 JavaScript,拥有 JS 的全部能力(变量、逻辑控制)。
+- **优化难度**:因为太灵活(动态性太强),React 很难像 Vue 那样做极致的编译时优化(虽然 React Compiler/React Forget 正在尝试解决这个问题)。React 更多依赖运行时的 Fiber 架构来调度更新。
+
+**代码对比:**
+
+```typescript
+// React JSX
+const element =
{isShow && }
;
+// 编译为: React.createElement('div', { className: 'foo' }, isShow && React.createElement(Span))
+```
+
+---
+
+## 2. Hooks 与 Composition API
+
+### Q3: `useEffect` 的依赖数组 (Dependency Array) 为什么容易产生闭包陷阱?与 Vue `watch` 有何不同?
+
+**Vue 3 视角解析:**
+Vue 的 `watchEffect` 自动收集依赖,`watch` 也可以直观地监听 ref。Vue 的组件 setup 只运行一次,闭包问题较少。
+
+**React 原理:**
+React 函数组件**每次渲染都会重新执行**。
+- **闭包陷阱**:如果在 `useEffect` 中使用了某个 state 但没放入依赖数组,`useEffect` 内部引用的就是**上一次渲染时的旧变量**(闭包捕获了旧值)。
+- **Stale Closure**:这是 React Hooks 最核心的痛点之一。
+
+**示例:**
+
+```typescript
+function Counter() {
+ const [count, setCount] = useState(0);
+
+ useEffect(() => {
+ const timer = setInterval(() => {
+ // 错误:这里的 count 永远是 0 (第一次渲染时的闭包)
+ console.log(count);
+ // 修正:setCount(c => c + 1) 或将 count 加入依赖数组
+ }, 1000);
+ return () => clearInterval(timer);
+ }, []); // [] 导致 effect 只执行一次,捕获了初始作用域
+}
+```
+
+**面试回答要点:**
+1. **执行机制**:Hooks 依赖于函数组件的多次执行,利用闭包保存状态。
+2. **依赖数组**:必须诚实地列出所有依赖,否则会读取到旧值。
+3. **对比 Vue**:Vue 的 setup 仅执行一次,响应式数据是引用的 Proxy,不存在"旧值"问题,心智负担更小;React 需要开发者手动维护依赖。
+
+### Q4: 为什么 React Hooks 不能写在条件语句(if/for)里?
+
+**Vue 3 视角解析:**
+Vue Composition API (`ref`, `reactive`) 可以随便写,因为 setup 只跑一次,变量声明了就在那。
+
+**React 原理:**
+React 内部通过**链表**(Linked List)来存储 Hooks 的状态。
+- **顺序很重要**:React 没有名字来区分 `useState(1)` 和 `useState(2)`,它完全依赖**调用顺序**来对应状态。
+- 如果放在 `if` 里,某次渲染跳过了一个 Hook,后面的 Hook 拿到的状态就会错位(比如把 `name` 的 state 给了 `age`)。
+
+**源码简化逻辑:**
+```javascript
+// 伪代码
+let hooks = [];
+let currentHookIndex = 0;
+
+function useState(initial) {
+ const hook = hooks[currentHookIndex] || { state: initial };
+ hooks[currentHookIndex] = hook;
+ currentHookIndex++; // 索引自增,依赖顺序
+ return [hook.state, setState];
+}
+```
+
+---
+
+## 3. Fiber 架构与并发模式
+
+### Q5: 什么是 React Fiber?它解决了什么问题?(对比 Vue 的更新机制)
+
+**Vue 3 视角解析:**
+Vue 的更新是**细粒度**的。组件级 Watcher 知道具体哪个组件变了,更新过程通常很快,不需要"时间切片"这种复杂机制。
+
+**React 原理:**
+React 的更新通常是**全量递归**(从根节点或 Context Provider 开始)。在 React 15(Stack Reconciler)时代,一旦开始 Diff,就必须递归到底,中间无法中断。如果树很深,JS 线程被占用超过 16ms,页面就会掉帧卡顿。
+
+**Fiber 架构:**
+1. **数据结构**:将递归的树结构转变为**链表**结构(Fiber Node)。这使得遍历可以**暂停、中止、恢复**。
+2. **时间切片 (Time Slicing)**:将渲染任务拆分成小块。浏览器空闲时(`requestIdleCallback` 概念)执行一部分 Diff,有高优先级任务(如用户输入)插队时,暂停低优先级任务。
+3. **双缓存 (Double Buffering)**:在内存中构建好新的 Fiber 树(workInProgress tree),构建完成后一次性替换 Current tree,减少页面闪烁。
+
+**面试回答要点:**
+- **核心目标**:实现**并发渲染 (Concurrent Rendering)**,解决 CPU 密集型更新导致的页面卡顿。
+- **实现方式**:将同步的递归 Diff 改为异步的可中断遍历。
+
+---
+
+## 4. 状态管理与组件通信
+
+### Q6: Redux/Zustand 与 Vuex/Pinia 的区别?
+
+**Vue 3 视角解析:**
+Pinia 本质是基于 Proxy 的全局响应式对象,非常直观,修改 state 直接赋值即可。
+
+**React 原理:**
+Redux 是典型的**单向数据流** + **不可变数据**。
+- **Action -> Reducer -> New Store**。
+- 必须返回新的 State 对象,不能直接修改。
+- **Context API**:React 自带的跨组件通信,但有性能缺陷(Provider 更新,所有 Consumer 强制重渲染),通常配合 `useMemo` 优化,或者使用 Zustand/Recoil 等库。
+
+**Zustand (推荐)**:
+Zustand 的用法非常像 Vue 3 的 Composition API + Pinia,去除了 Redux 的样板代码,支持直接修改(通过 immer)或返回新对象,是目前 React 生态中最符合直觉的库。
+
+---
+
+## 5. 性能优化机制
+
+### Q7: `useMemo` 和 `useCallback` 是做什么的?Vue 为什么很少需要它们?
+
+**Vue 3 视角解析:**
+Vue 的 `computed` 自动缓存,组件更新也是自动精确控制的。子组件 props 没变,Vue 默认就不会去递归更新子组件(除非插槽等情况)。
+
+**React 原理:**
+React 组件默认行为:**父组件更新,所有子组件无条件重新渲染**。
+- **性能浪费**:即使子组件 props 没变,也会运行。
+- **React.memo**:高阶组件,用于包裹子组件,做 Props 的浅比较(类似 Vue 的默认行为)。
+- **useCallback**:
+ - 问题:父组件每次 Render,定义的函数 `const handleClick = () => {}` 都是**新引用**。
+ - 后果:传给子组件时,`React.memo` 发现 props.onClick 变了,导致子组件重渲染。
+ - 解决:`useCallback` 缓存函数引用,只有依赖变了才生成新函数。
+- **useMemo**:缓存计算结果(类似 Vue `computed`),避免每次 Render 都进行昂贵计算。
+
+**面试回答要点:**
+- React 的优化是**手动挡**(开发者决定何时缓存),Vue 是**自动挡**(响应式系统自动处理)。
+- 滥用 `useMemo` 也有开销,只在昂贵计算或引用稳定性关键时使用。
+
+---
+
+## 6. Diff 算法深度解析
+
+### Q8: React Diff 算法与 Vue Diff 算法的区别?
+
+**Vue 3 视角解析:**
+Vue 2 使用双端 Diff,Vue 3 使用**最长递增子序列 (LIS)** 算法处理乱序移动,效率极高。
+
+**React 原理:**
+React Fiber 的 Diff 算法(Reconciliation)相对简单,采用**单向遍历**。
+1. **仅右移**:React 在对比数组列表时,采用 `lastPlacedIndex` 指针。如果新节点在旧集合中存在且位置靠后,则不动;如果位置靠前,则向后移动。
+2. **为什么不用双端?**:Fiber 结构是单向链表(Sibling 指针),很难像数组那样方便地从尾部开始对比(没有反向指针)。
+3. **Key 的重要性**:和 Vue 一样,Key 是识别节点的唯一标识。没有 Key,React 只能按索引对比,导致状态错乱或性能低下。
+
+**总结对比:**
+- **Vue**:双端比较 / 最长递增子序列 -> 移动次数最少,算法复杂度稍高但 DOM 操作最少。
+- **React**:单向遍历 / 右移策略 -> 算法简单,但在特定逆序场景下 DOM 移动次数可能多于 Vue。
+
+---
+
+## 7. TypeScript 实战差异
+
+### Q9: React.FC 还需要用吗?Hooks 怎么定义泛型?
+
+**Vue 3 视角解析:**
+Vue `defineComponent` 或 `
+```
+
+**互操作机制:**
+
+```javascript
+// Vapor 组件在 VDOM 中的表现
+// Vue 会为 Vapor 组件创建一个特殊的 VNode 包装器
+
+const VaporComponentVNode = {
+ type: VaporComponent,
+ __vapor: true, // 标记为 Vapor 组件
+
+ // 挂载时直接调用 Vapor 渲染函数
+ mount(container) {
+ const instance = createVaporInstance(VaporComponent)
+ const root = instance.render()
+ container.appendChild(root)
+ },
+
+ // 更新由 Vapor 的响应式系统自动处理
+ // VDOM 侧不需要 diff 这个组件的内部
+}
+```
+
+**选择策略:**
+
+| 组件类型 | 推荐模式 | 原因 |
+|----------|----------|------|
+| 性能关键组件 | Vapor | 细粒度更新,零 VDOM 开销 |
+| 高度动态组件 | VDOM | 更灵活的动态渲染 |
+| 第三方组件库 | VDOM | 兼容性 |
+| 简单展示组件 | Vapor | 更小的运行时 |
+| 复杂状态组件 | 视情况 | 评估更新频率和模式 |
+
+---
+
+### Q22: Vapor Mode 的优势、局限性和适用场景是什么?
+
+**答案:**
+
+**优势:**
+
+```javascript
+// 1. 更小的运行时体积
+// VDOM 运行时: ~50KB (gzip ~16KB)
+// Vapor 运行时: ~6KB (gzip ~2KB)
+
+// 2. 更快的更新性能
+// 基准测试(更新 1000 行表格):
+// VDOM: ~15ms
+// Vapor: ~3ms(快 5 倍)
+
+// 3. 更低的内存占用
+// 无 VNode 对象创建,GC 压力更小
+
+// 4. 更快的首次渲染
+// 无需创建完整的 VNode 树
+```
+
+**局限性:**
+
+```javascript
+// 1. 动态组件支持有限
+// ❌ 不支持
+
+
+// 2. 渲染函数/JSX 不支持
+// Vapor 依赖模板编译,不支持手写渲染函数
+export default {
+ render() {
+ return h('div', this.msg) // ❌ 不能使用 Vapor
+ }
+}
+
+// 3. 部分动态指令受限
+// 需要编译时确定的指令
+
+// 4. 生态兼容性
+// 部分依赖 VDOM 的组件库可能不兼容
+```
+
+**适用场景评估:**
+
+```javascript
+// ✅ 推荐使用 Vapor Mode
+- 性能敏感的移动端应用
+- 大量数据展示的表格/列表
+- 嵌入式/资源受限环境
+- 追求极致首屏性能的场景
+- 简单的交互组件
+
+// ⚠️ 谨慎使用
+- 高度动态的组件结构
+- 需要手写渲染函数的场景
+- 重度依赖第三方 UI 库
+
+// ❌ 不适合
+- 需要 JSX 的项目
+- 动态组件为核心的应用
+```
+
+**性能基准对比:**
+
+```
+操作类型 VDOM Vapor 提升
+─────────────────────────────────────────────
+创建 1000 行 45ms 12ms 3.8x
+更新全部行 38ms 8ms 4.8x
+更新单行 4ms 0.3ms 13.3x
+交换两行 6ms 0.8ms 7.5x
+删除行 8ms 2ms 4.0x
+内存占用 (1000行) 12MB 3MB 4.0x
+运行时体积 50KB 6KB 8.3x
+```
+
+---
+
+### Q23: 如何在项目中渐进式采用 Vapor Mode?
+
+**答案:**
+
+**步骤 1:升级依赖**
+
+```bash
+# 确保 Vue 版本支持 Vapor(3.5+)
+npm install vue@latest
+npm install @vitejs/plugin-vue@latest
+```
+
+**步骤 2:配置构建工具**
+
+```javascript
+// vite.config.js
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+export default defineConfig({
+ plugins: [
+ vue({
+ vapor: true,
+ // 可选:指定 Vapor 组件的文件模式
+ vaporPatterns: [
+ '**/*.vapor.vue',
+ '**/vapor/**/*.vue'
+ ]
+ })
+ ]
+})
+```
+
+**步骤 3:识别适合迁移的组件**
+
+```javascript
+// 分析工具:识别性能热点
+// 1. 使用 Vue Devtools Performance 面板
+// 2. 找出频繁更新的组件
+// 3. 评估组件复杂度
+
+// 适合迁移的特征:
+// - 纯展示组件
+// - 列表/表格组件
+// - 频繁更新的状态展示
+// - 不依赖动态组件/渲染函数
+```
+
+**步骤 4:逐步迁移**
+
+```vue
+
+
+
+
+
+
+ |
+ {{ cell.value }}
+ |
+
+
+
+
+
+```
+
+**步骤 5:性能验证**
+
+```javascript
+// 添加性能监控
+import { onMounted, onUpdated } from 'vue'
+
+let updateStart = 0
+
+onBeforeUpdate(() => {
+ updateStart = performance.now()
+})
+
+onUpdated(() => {
+ const duration = performance.now() - updateStart
+ console.log(`Update took: ${duration.toFixed(2)}ms`)
+
+ // 上报到监控系统
+ reportMetric('component_update', duration)
+})
+```
+
+**迁移策略建议:**
+
+```
+阶段 1(试点)
+├── 选择 1-2 个性能关键组件
+├── 转换为 Vapor Mode
+└── 验证性能提升和功能正确性
+
+阶段 2(扩展)
+├── 迁移更多展示型组件
+├── 建立 Vapor 组件开发规范
+└── 团队培训
+
+阶段 3(优化)
+├── 监控生产环境性能
+├── 根据数据调整策略
+└── 持续迭代优化
+```
+
+---
+
+## 9. Vue 3 与 Vue 2 核心区别
+
+### Q24: Vue 3 相比 Vue 2 做了哪些重大改进?
+
+**答案:**
+
+**1. 架构层面:**
+
+| 改进点 | Vue 2 | Vue 3 |
+|--------|-------|-------|
+| 响应式系统 | Object.defineProperty | Proxy |
+| 代码组织 | Options API | Composition API |
+| 源码结构 | 单一仓库 | Monorepo(@vue/reactivity 可独立使用) |
+| TypeScript | 额外配置 | 原生支持 |
+| Tree-shaking | 有限 | 全面支持 |
+
+**2. 新增特性:**
+
+```javascript
+// Teleport:传送组件到任意 DOM 位置
+
+
+
+
+// Suspense:异步组件加载状态处理
+
+
+
+
+
+
+
+
+
+// 多根节点(Fragments)
+
+
+ ...
+
+
+
+// createRenderer:自定义渲染器
+import { createRenderer } from '@vue/runtime-core'
+const { render } = createRenderer({
+ createElement(type) { /* ... */ },
+ insert(el, parent) { /* ... */ },
+ // ...
+})
+```
+
+**3. 破坏性变更:**
+
+```javascript
+// v-model 变化
+// Vue 2: value + input
+// Vue 3: modelValue + update:modelValue
+
+// 移除的 API
+// $on, $off, $once(使用 mitt 替代)
+// $children(使用 ref + expose)
+// $listeners(合并到 $attrs)
+// filters(使用 computed 或方法)
+
+// v-for 和 v-if 优先级
+// Vue 2: v-for 优先
+// Vue 3: v-if 优先
+
+// 生命周期重命名
+// destroyed → unmounted
+// beforeDestroy → beforeUnmount
+```
+
+---
+
+## 10. 实战场景题
+
+### Q25: 如何实现一个防抖的搜索输入框?
+
+**答案:**
+
+```javascript
+// 方案1:使用 watchEffect + 自定义防抖
+import { ref, watchEffect } from 'vue'
+
+function useDebouncedSearch(delay = 300) {
+ const searchTerm = ref('')
+ const debouncedTerm = ref('')
+
+ watchEffect((onCleanup) => {
+ const timer = setTimeout(() => {
+ debouncedTerm.value = searchTerm.value
+ }, delay)
+
+ onCleanup(() => clearTimeout(timer))
+ })
+
+ return { searchTerm, debouncedTerm }
+}
+
+// 使用
+const { searchTerm, debouncedTerm } = useDebouncedSearch(300)
+
+watch(debouncedTerm, async (term) => {
+ if (term) {
+ results.value = await fetchResults(term)
+ }
+})
+
+// 方案2:使用 VueUse
+import { useDebounceFn, refDebounced } from '@vueuse/core'
+
+const searchTerm = ref('')
+const debouncedTerm = refDebounced(searchTerm, 300)
+
+// 或者防抖函数
+const debouncedSearch = useDebounceFn((term) => {
+ fetchResults(term)
+}, 300)
+
+watch(searchTerm, debouncedSearch)
+```
+
+---
+
+### Q26: 如何封装一个可复用的 useFetch 组合式函数?
+
+**答案:**
+
+```javascript
+import { ref, shallowRef, watchEffect, toValue } from 'vue'
+
+export function useFetch(url, options = {}) {
+ const data = shallowRef(null)
+ const error = shallowRef(null)
+ const loading = ref(false)
+
+ const execute = async () => {
+ loading.value = true
+ error.value = null
+
+ const controller = new AbortController()
+
+ try {
+ const response = await fetch(toValue(url), {
+ ...options,
+ signal: controller.signal
+ })
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`)
+ }
+
+ data.value = await response.json()
+ } catch (e) {
+ if (e.name !== 'AbortError') {
+ error.value = e
+ }
+ } finally {
+ loading.value = false
+ }
+
+ return controller
+ }
+
+ // 自动执行并支持响应式 URL
+ watchEffect((onCleanup) => {
+ const controller = execute()
+ onCleanup(() => controller?.abort())
+ })
+
+ const refetch = () => execute()
+
+ return {
+ data,
+ error,
+ loading,
+ refetch
+ }
+}
+
+// 使用
+const userId = ref(1)
+const { data: user, loading, error, refetch } = useFetch(
+ () => `/api/users/${userId.value}`
+)
+
+// 改变 userId 会自动重新请求
+userId.value = 2
+```
+
+---
+
+### Q27: 如何实现一个无限滚动列表?
+
+**答案:**
+
+```javascript
+// useInfiniteScroll.js
+import { ref, onMounted, onUnmounted } from 'vue'
+
+export function useInfiniteScroll(loadMore, options = {}) {
+ const {
+ threshold = 100,
+ container = null
+ } = options
+
+ const loading = ref(false)
+ const finished = ref(false)
+
+ const handleScroll = async (e) => {
+ if (loading.value || finished.value) return
+
+ const target = container?.value || document.documentElement
+ const scrollHeight = target.scrollHeight
+ const scrollTop = target.scrollTop
+ const clientHeight = target.clientHeight
+
+ if (scrollHeight - scrollTop - clientHeight < threshold) {
+ loading.value = true
+ const hasMore = await loadMore()
+ loading.value = false
+
+ if (!hasMore) {
+ finished.value = false
+ }
+ }
+ }
+
+ onMounted(() => {
+ const target = container?.value || window
+ target.addEventListener('scroll', handleScroll)
+ })
+
+ onUnmounted(() => {
+ const target = container?.value || window
+ target.removeEventListener('scroll', handleScroll)
+ })
+
+ return { loading, finished }
+}
+
+// 使用 Intersection Observer 的更优方案
+export function useInfiniteScrollV2(callback) {
+ const target = ref(null)
+ const loading = ref(false)
+
+ let observer = null
+
+ onMounted(() => {
+ observer = new IntersectionObserver(async ([entry]) => {
+ if (entry.isIntersecting && !loading.value) {
+ loading.value = true
+ await callback()
+ loading.value = false
+ }
+ })
+
+ if (target.value) {
+ observer.observe(target.value)
+ }
+ })
+
+ onUnmounted(() => {
+ observer?.disconnect()
+ })
+
+ return { target, loading }
+}
+
+// 使用
+
+ {{ item.name }}
+
+ 加载中...
+
+
+
+
+```
+
+---
+
+### Q28: 如何处理 Vue 3 中的错误边界?
+
+**答案:**
+
+```javascript
+// ErrorBoundary.vue
+
+
+
+
+
出错了!
+
{{ error.message }}
+
+
+
+
+
+// 使用
+
+
+
+
+// 全局错误处理
+app.config.errorHandler = (err, instance, info) => {
+ console.error('Global error:', err)
+ console.log('Component:', instance)
+ console.log('Error info:', info)
+
+ // 发送到错误监控服务
+ Sentry.captureException(err)
+}
+
+// 处理异步错误
+app.config.warnHandler = (msg, instance, trace) => {
+ console.warn('Warning:', msg)
+}
+```
+
+---
+
+## 总结
+
+Vue 3 面试重点掌握:
+
+1. **响应式原理**:Proxy、依赖收集、触发更新的完整流程
+2. **Composition API**:setup、ref/reactive、watch/computed 原理
+3. **编译优化**:静态提升、PatchFlags、Block Tree
+4. **Diff 算法**:快速 Diff、最长递增子序列
+5. **性能优化**:v-memo、shallowRef、组件懒加载
+6. **实战能力**:组合式函数封装、状态管理、错误处理
+
+---
+
+> 持续更新中,欢迎补充!