Tabula相册整理工具2026
27.5MB · 2026-04-07
模板语法:{{ }} 文本插值、v-html 输出 HTML
指令:
v-bind、v-on、v-model、v-if/v-else-if/v-else、v-show、v-for、v-pre、v-cloak、v-onceVue.directive(Vue 2)/ app.directive(Vue 3),局部 directives 选项Vue 2:基于 Object.defineProperty,递归遍历对象属性,无法检测:
Vue.set / this.$set)Vue.set)splice 等)Vue 3:基于 Proxy,可动态添加属性、数组索引修改,性能更优,支持 Map、Set 等原生集合的响应式
响应式原理:
data 中的属性进行响应式处理(Vue 2 用 Object.defineProperty,Vue 3 用 Proxy)。Watcher(观察者)添加到该数据的依赖列表(Dep)中。Dep 通知所有依赖它的 Watcher 执行更新。Watcher 更新时并不立即执行 DOM 操作,而是将自身推入一个队列,在下一个事件循环(microtask)中统一执行,并利用 nextTick 提供更新后的回调。| API | 说明 |
|---|---|
ref() | 声明任意类型的响应式数据,需通过 .value 访问。 |
reactive() | 声明对象/数组类型的响应式数据,可直接访问属性。 |
computed() | 定义计算属性,基于响应式依赖缓存结果。 |
watch() | 特定数据源,在数据变化时执行副作用。 |
watchEffect() | 自动追踪其内部使用的响应式数据,并在数据变化时立即重新运行。 |
onMounted(), onUpdated(), onUnmounted() 等 | 组件生命周期不同阶段执行的钩子函数,用法与选项式 API 对应。 |
provide(), inject() | 用于跨层级组件通信,祖先组件提供数据,后代组件注入使用。 |
toRefs(), toRef(), isRef(), unref() 等 | 用于处理 ref / reactive 对象的辅助函数,帮助进行响应式转换和判断。 |
defineProps(), defineEmits() | 在 <script setup> 中声明组件的 props 和 emits,享受完整类型推导。 |
defineExpose() | 在 <script setup> 中声明当前组件暴露给父组件的属性或方法。 |
defineOptions() | 在 <script setup> 中声明组件名 (name) 或 inheritAttrs 等选项。 |
| 组件 | 说明 |
|---|---|
<component> | 用于动态渲染不同组件的“元组件”,通过 is 属性决定。 |
<transition> | 为单个元素或组件添加进入/离开过渡动画。 |
<transition-group> | 为列表中的多个元素或组件添加过渡动画。 |
<keep-alive> | 缓存动态组件,避免重复渲染和状态丢失。 |
<teleport> | 将组件模板的一部分渲染到 DOM 树中的指定位置。 |
<suspense> | 管理异步组件或依赖异步数据的组件,在等待时显示后备内容。 |
<slot> | 作为组件模板中的插槽出口,接收父组件分发的内容。 |
| 指令 | 说明 |
|---|---|
v-model | 在表单元素或组件上创建双向绑定。 |
v-if, v-else-if, v-else | 条件渲染,为 false 时不渲染元素。 |
v-show | 条件渲染,通过 CSS 的 display 属性切换。 |
v-for | 基于源数据多次渲染元素或模板块。 |
v-on (@) | 绑定事件器。 |
v-bind (:) | 动态地绑定一个或多个属性。 |
v-slot (#) | 用于声明具名插槽或作用域插槽。 |
| 阶段 | Vue 2 钩子 | Vue 3 钩子(Options API) | Vue 3 钩子(Composition API) |
|---|---|---|---|
| 初始化 | beforeCreate, created | 同 | setup() 代替 beforeCreate/created |
| 挂载 | beforeMount, mounted | 同 | onBeforeMount, onMounted |
| 更新 | beforeUpdate, updated | 同 | onBeforeUpdate, onUpdated |
| 卸载 | beforeDestroy, destroyed | beforeUnmount, unmounted | onBeforeUnmount, onUnmounted |
| 错误捕获 | errorCaptured | 同 | onErrorCaptured |
| 其他 | activated, deactivated(keep-alive) | 同 | onActivated, onDeactivated |
| 调试 | renderTracked, renderTriggered(开发) | 同 | onRenderTracked, onRenderTriggered |
slot-scope in Vue 2,v-slot in Vue 2.6+ & Vue 3)v-slot 统一为指令语法,slot 和 slot-scope 被废弃钩子函数:
bind, inserted, update, componentUpdated, unbindbeforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted参数:el, binding, vnode, prevVnode
{{ msg | filter }})及全局/局部定义<transition> 单元素过渡<transition-group> 多元素/列表过渡v-enter-from/v-enter-to 等(Vue 3 命名变化)@before-enter, @enter, @after-enter 等| 方式 | Vue 2 | Vue 3 |
|---|---|---|
| props / $emit | 支持 | 支持,emit 需在 setup 中声明 |
| v-model | 单个,value + input | 可多个,modelValue + update:modelValue,支持自定义修饰符 |
| parent / $children | $children 存在 | 移除 $children,推荐 ref + $parent 或组合式 API |
| provide / inject | 默认非响应式,可传递响应式对象 | 支持响应式传递,可提供 ref/reactive |
| event bus | new Vue() 作为总线 | 推荐用 mitt 等第三方库 |
| Vuex | Vuex 3 | Vuex 4 / Pinia |
| slot 作用域 | slot-scope | v-slot 统一语法 |
| 组合式 API | 无 | 可直接使用 ref 传递,逻辑复用更灵活 |
| 特性 | Vue Router 3(Vue 2) | Vue Router 4(Vue 3) |
|---|---|---|
| 创建方式 | new VueRouter(...) | createRouter({ ... }) |
| 模式 | mode: 'history' / 'hash' | history: createWebHistory() / createWebHashHistory() |
| 路由守卫 | beforeEach / beforeResolve / afterEach | 同,但支持组合式 API 中的 onBeforeRouteUpdate 等 |
| 路由元信息 | meta | 同 |
| 动态路由 | addRoutes | addRoute,且支持动态删除 |
| 导航故障 | NavigationFailureType | 更完善的类型 |
| 组合式 API | 不支持 | useRouter、useRoute |
| 特性 | Vuex 3/4 | Pinia |
|---|---|---|
| 设计理念 | 基于 Flux,强调 mutations / actions / getters | 更简洁,直接修改 state,支持组合式 API |
| 类型推断 | 需要额外处理 | 原生 TypeScript 支持 |
| 模块化 | 通过 modules | 通过多个 store 自然分割 |
| 异步处理 | actions 中 | actions 中,可直接使用 async/await |
| 代码量 | 较多模板代码 | 更少,更直观 |
| 热更新 | 有限支持 | 支持 store 热更新 |
| Vue 3 推荐 | 可用,但官方转向 Pinia | 官方推荐,轻量且强大 |
| 特性 | Vue CLI(基于 webpack) | Vite |
|---|---|---|
| 启动速度 | 慢(打包后启动) | 极快(按需编译,原生 ES modules) |
| 生产构建 | 基于 webpack,配置灵活但复杂 | 基于 Rollup,预配置更简单 |
| 插件生态 | 丰富的 webpack 插件 | 插件系统兼容 Rollup 插件,且提供 Vite 插件 |
| 配置方式 | vue.config.js | vite.config.js |
| 开发环境 | HMR 较慢(大规模项目) | HMR 快速,保留状态 |
| 环境变量 | VUE_APP_* | VITE_* |
遍历 data 对象,对每个属性递归调用 defineReactive,为每个属性创建 Dep(依赖收集器)。
每个属性对应一个 Watcher(观察者),在渲染时收集依赖。
缺点:
Vue.set / this.$set)。arr[0] = xx 不触发更新,需用变异方法如 push, splice)。基于 Proxy 代理整个对象,可拦截 get、set、deleteProperty 等操作。
优点:
length 变化自动响应。Map、Set 等原生集合。Vue 2 通过 Object.defineProperty 劫持对象属性的 getter/setter 来实现响应式,但存在局限性,比如无法动态添加的属性,需要通过 Vue.set 处理。Vue 3 改用 Proxy,可以代理整个对象,支持多种操作拦截,解决了上述问题,同时性能更优。响应式核心是依赖收集和派发更新,在 getter 中收集依赖,在 setter 中触发更新,并通过异步队列实现批量更新
虚拟 DOM 是一种用 JS 对象模拟真实 DOM 的结构,通过 diff 算法对比新旧 VNode,找出差异并批量更新真实 DOM,减少了直接操作 DOM 的性能开销。Vue 2 的 diff 采用双端比较,Vue 3 则引入了静态提升和 patch flags,进一步优化了更新效率。key 是 diff 过程中识别节点的重要依据,使用稳定的 key 可以保证节点复用,避免渲染错误。
keep-alive 组件激活/停用。Vue 的异步更新队列。数据变化后,Vue 将开启一个队列,把同一个事件循环内的所有数据变化缓存起来,然后在下一个事件循环(microtask)统一执行 DOM 更新。$nextTick 的回调会在 DOM 更新完成后执行。
“$nextTick 利用 Promise 或 MutationObserver 等微任务机制,将回调延迟到下次 DOM 更新循环之后执行。我们常用来解决数据变化后立即操作 DOM 的问题,比如滚动到底部、获取元素宽高等。Vue 3 中同样有 nextTick 函数,可在组合式 API 中使用。
缓存不活动的组件实例,避免反复渲染。
内部维护一个缓存对象(键是组件的 key 或自身),当组件切换时,将被移除的组件实例保留在缓存中,而不是销毁。再次激活时从缓存取出复用,触发 activated 和 deactivated 钩子。
include / exclude:正则或数组,指定要缓存/不缓存的组件。max:最大缓存数,超出时根据 LRU 策略删除。created → mounted → activatedactivated(不会重新执行 created / mounted)deactivated“keep-alive 是一个抽象组件,它通过缓存 VNode 来保留组件状态,避免重复渲染。内部使用 LRU 算法管理缓存,可以通过 include 和 max 控制缓存策略。被缓存的组件会多出 activated 和 deactivated 钩子,用于在激活/停用时执行逻辑。
优点:
缺点:学习曲线稍陡,对初学者不够直观。
“选项式 API 将组件选项按类型划分,代码直观但逻辑分散。组合式 API 将相关逻辑聚合在 setup 中,通过组合函数实现复用,尤其适合大型复杂组件。Vue 3 并未废弃选项式 API,两者可混用,但组合式 API 提供了更好的逻辑复用能力和类型支持,是未来的推荐写法。”
“SSR 在服务端将 Vue 组件渲染成 HTML,发送给客户端,然后客户端进行激活。它主要解决 SPA 的 SEO 问题和首屏加载速度。但实现成本较高,需要处理服务端和客户端环境的差异,并关注服务器性能。通常我们会借助 Nuxt.js(Vue 2)或 Nuxt 3(Vue 3)这样的框架来简化 SSR 开发。”
createApp 替代 new Vue,全局配置隔离。$children、$on/$once/$off、v-on.native 等。v-model 默认 prop 和事件变化,支持多个绑定。v-if 与 v-for 优先级改变。“Vue 3 相比 Vue 2 在响应式系统、组合式 API、性能、TypeScript 支持等方面有重大改进。它引入了 Teleport、Suspense 等内置组件,并用 createApp 创建应用,避免全局污染。虽然有一些破坏性变更,但官方提供了迁移构建和工具帮助升级。Vue 3 也带来了更现代的构建工具 Vite,提升了开发体验。”
defineProps – 接收父组件传递的数据作用:声明组件的 props(属性),代替传统的 props 选项。
基本用法:
<script setup>
// 运行时声明(自动推断类型)
const props = defineProps(['title', 'count'])
// 带类型的声明(TypeScript)
const props = defineProps<{
title: string
count?: number // 可选
}>()
</script>
父组件使用:
<MyComponent title="Hello" :count="10" />
defineEmits – 向父组件发送事件作用:声明组件可以触发的事件。
<script setup>
// 简单声明
const emit = defineEmits(['update', 'delete'])
// 带参数验证(TypeScript)
const emit = defineEmits<{
(e: 'update', id: number): void
(e: 'delete', name: string): void
}>()
// 触发事件
emit('update', 123)
</script>
父组件:
<MyComponent @update="handleUpdate" @delete="handleDelete" />
defineExpose – 暴露组件内部属性/方法给父组件(通过 ref)作用:默认 <script setup> 下的组件是关闭的,父组件无法通过 ref 访问其内部成员。使用 defineExpose 明确暴露。
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
// 只暴露 increment 和 count,其他不暴露
defineExpose({
increment,
count
})
</script>
父组件访问:
<template>
<MyComponent ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
const childRef = ref()
onMounted(() => {
childRef.value.increment() // 调用子组件方法
console.log(childRef.value.count) // 读取子组件数据
})
</script>
defineOptions – 设置组件选项(Vue 3.3+)作用:在 <script setup> 中声明组件名、继承属性、自定义选项等,无需单独的 <script> 块。
<script setup>
defineOptions({
name: 'MyCustomName', // 组件名称
inheritAttrs: false, // 是否继承非 prop 属性
// 其他选项(如 components、directives 一般不在这里,但可自定义)
})
</script>
典型场景:
$attrs)| 特性 | watch | watchEffect |
|---|---|---|
| 依赖收集 | 显式指定要的数据源(ref、reactive 属性、getter 函数) | 自动收集回调函数中使用的所有响应式数据 |
| 初始执行 | 默认不执行,数据第一次变化时才执行(可配置 immediate: true) | 立即执行一次,同时收集依赖 |
| 访问新旧值 | 回调中提供旧值和新值 | 只能访问新值(无法直接获取旧值) |
| 多个源 | 支持同时多个数据源(数组形式) | 自动收集多个依赖,无需显式指定 |
| 精准控制 | 可以配置 deep、flush、immediate 等选项 | 只有 flush 选项(以及 onTrack/onTrigger 调试) |
| 停止 | 调用返回的函数 | 同样返回停止函数 |
| 适用场景 | 需要知道具体哪个数据变化、需要旧值、需要惰性执行 | 简单副作用,自动跟踪依赖,不需要旧值 |
<script setup>
import { ref, reactive, watch } from 'vue'
const count = ref(0)
const state = reactive({ name: 'Vue', age: 3 })
// 单个 ref
watch(count, (newVal, oldVal) => {
console.log(`count 从 ${oldVal} 变为 ${newVal}`)
})
// getter 函数
watch(
() => state.age,
(newAge, oldAge) => {
console.log(`年龄从 ${oldAge} 变为 ${newAge}`)
}
)
// 多个源(数组)
watch([count, () => state.age], ([newCount, newAge], [oldCount, oldAge]) => {
console.log(`count: ${oldCount}->${newCount}, age: ${oldAge}->${newAge}`)
})
// 立即执行 + 深度
watch(
() => state,
(newVal, oldVal) => {
console.log('state 变化了', newVal)
},
{ immediate: true, deep: true }
)
</script>
<script setup>
import { ref, reactive, watchEffect } from 'vue'
const count = ref(0)
const state = reactive({ name: 'Vue', age: 3 })
// 自动收集依赖:count 和 state.age
watchEffect(() => {
console.log(`count: ${count.value}, age: ${state.age}`)
})
// 初始立即输出:count: 0, age: 3
// 之后任何依赖变化都会重新执行
// 停止
const stop = watchEffect(() => { /* ... */ })
stop() // 手动停止
</script>
<!-- Ancestor.vue -->
<script setup>
import { provide, ref } from 'vue'
// 提供普通值
provide('theme', 'dark')
// 提供响应式数据(推荐)
const count = ref(0)
const updateCount = () => count.value++
provide('count', count)
provide('updateCount', updateCount)
</script>
<!-- Descendant.vue -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme', 'light') // 默认值 'light'
const count = inject('count')
const updateCount = inject('updateCount')
// 使用
console.log(theme) // 'dark'
count.value++ // 响应式更新
updateCount() // 调用方法
</script>
toRefs – 将响应式对象转换为普通对象,每个属性都是 ref作用:解构 reactive 对象时保持响应性。
import { reactive, toRefs } from 'vue'
const state = reactive({ count: 0, name: 'Vue' })
// 直接解构会丢失响应性
let { count, name } = state
count++ // 不会触发视图更新
// 使用 toRefs 包装
const stateRefs = toRefs(state)
const { count, name } = stateRefs
count.value++ // 响应式生效
原理:toRefs 为每个属性创建一个 ref 链接到原对象的对应属性。
toRef – 为响应式对象的单个属性创建 ref作用:保持对源对象属性的响应式引用,常用于将 props 的某个属性转为 ref 以便传递。
import { reactive, toRef } from 'vue'
const state = reactive({ count: 0 })
const countRef = toRef(state, 'count')
countRef.value++ // 同时修改 state.count
console.log(state.count) // 1
典型场景:组合函数接收 props 中的某个属性并保持响应性。
// useFeature.js
import { toRef, watchEffect } from 'vue'
export function useFeature(propRef) {
const propVal = toRef(propRef) // 确保是 ref
watchEffect(() => {
console.log(propVal.value)
})
}
isRef – 判断某个值是否为 refimport { ref, reactive, isRef } from 'vue'
const count = ref(0)
const state = reactive({})
console.log(isRef(count)) // true
console.log(isRef(state)) // false
unref – 如果参数是 ref 则返回其 value,否则返回参数本身作用:方便地获取值,无需手动判断 .value。
import { ref, unref } from 'vue'
const count = ref(0)
const plain = 42
console.log(unref(count)) // 0
console.log(unref(plain)) // 42
// 等价于
function myUnref(val) {
return isRef(val) ? val.value : val
}
常用场景:在组合函数中,参数可能是 ref 也可能是普通值,使用 unref 统一处理。
React 是 Meta 开源的 JavaScript UI 库,专注于构建用户界面。核心特点:
JSX 是 React.createElement 的语法糖。
// JSX 写法
const element = <h1 className="title">Hello React</h1>;
// 编译后
const element = React.createElement('h1', { className: 'title' }, 'Hello React');
浏览器无法识别 JSX,需要通过 Babel 编译为普通 JS 代码才能执行
React 组件间通信方式取决于组件关系,主要方式如下:
| 方式 | 适用场景 | 示例 |
|---|---|---|
| Props | 父→子传递数据 | <Child message={msg} /> |
| 回调函数 | 子→父传递数据 | 父传函数给子,子调用 props.onChildData(data) |
| Context API | 跨层级组件通信(避免 props 逐层传递) | createContext + useContext |
| 状态管理库 | 大型应用全局状态 | Redux Toolkit、Zustand、Jotai |
| Refs | 直接访问 DOM 或子组件实例 | useRef + ref 属性 |
| 自定义 Hooks | 复用状态逻辑 | useAuth、useFetch 等 |
| 高阶组件(HOC) | 共享逻辑(较少使用,Hooks 更优) | 接收组件返回增强组件 |
| Event Bus(事件总线) | 任意组件通信(非 React 原生) | mitt 等第三方库 |
| Hook | 说明 |
|---|---|
useState | 在函数组件中添加和管理局部状态,返回当前状态和更新函数。 |
useReducer | 用于管理包含多个子值或依赖先前状态的复杂组件逻辑,基于 reducer 模式。 |
useContext | 读取并订阅组件中的 Context 值,避免 props 逐层传递。 |
useRef | 声明一个可变引用,可以保存任何可变值,最常见的用途是访问 DOM 元素。 |
useImperativeHandle | 自定义通过 ref 暴露给父组件的实例值,通常与 forwardRef 配合使用。 |
useEffect | 将组件连接到外部系统并处理副作用,如数据获取、订阅、手动 DOM 操作,在渲染后执行。 |
useLayoutEffect | 在浏览器重新绘制屏幕之前同步触发,用法与 useEffect 相同,但会阻塞视觉更新。 |
useInsertionEffect | 在 DOM 变异之前触发,专为 CSS-in-JS 库注入样式而设计。 |
useMemo | 缓存昂贵计算的结果,避免在每次渲染时重复计算,仅在依赖项变化时重新计算。 |
useCallback | 缓存函数定义,防止因函数重新创建导致的子组件不必要重新渲染。 |
useTransition | 将状态更新标记为"过渡",这种更新可以被中断,以避免阻塞用户界面。 |
useDeferredValue | 延迟更新 UI 的某一部分,以优先响应用户输入。 |
useId | 生成在客户端和服务器上保持稳定的唯一 ID,主要用于可访问性属性。 |
useDebugValue | 在 React DevTools 中为自定义 Hook 添加标签,用于调试。 |
useSyncExternalStore | 允许函数组件订阅外部 store(如第三方状态管理库或浏览器 API)。 |
useOptimistic | 允许在后台操作完成前乐观地更新 UI,提供即时反馈。 |
useActionState | 管理表单 action 的状态,包括 pending 状态和返回数据。 |
use | 通用的资源读取 API,用于读取 Promise 或 Context 等资源的值,可以在条件语句中调用。 |
这些是可以在 JSX 中使用的 React 内置组件,以 Symbol 常量形式导出。
| 组件 | 说明 |
|---|---|
<Fragment> | 让你无需向 DOM 添加额外节点即可对子元素列表进行分组,支持简写 <>...</>。 |
<Profiler> | 用于编程式测量 React 应用的渲染性能。 |
<StrictMode> | 用于检测应用中潜在问题的工具,不会渲染任何可见 UI。 |
<Suspense> | 允许在子组件完成加载前显示一个回退 UI。 |
<Activity> | React 19 新增 API,用于隐藏和恢复其子组件的 UI 和内部状态。 |
| API | 说明 |
|---|---|
createContext | 创建一个 Context 对象,可供组件向其子组件提供数据,搭配 useContext 使用。 |
forwardRef | 允许组件将 DOM 节点作为 ref 暴露给父组件,搭配 useRef 使用。 |
lazy | 允许在组件第一次被渲染前延迟加载其代码,实现代码分割。 |
memo | 允许组件在 props 未发生变化时跳过重新渲染,搭配 useMemo 和 useCallback 使用。 |
startTransition | 允许将状态更新标记为非紧急的,与 useTransition 类似但用于非 Hook 场景。 |
act | 在测试中用于包裹渲染和交互,确保在断言前所有更新已处理完毕。 |
createElement | 创建 React 元素,通常用 JSX 替代,但可在非 JSX 环境中使用。 |
cloneElement | 克隆并返回一个新的 React 元素,可覆盖原元素的 props。 |
isValidElement | 检查某个值是否为 React 元素。 |
Children | 提供 map、forEach、count、only、toArray 等工具方法,用于处理 props.children 不透明数据结构。 |
Component | 定义类组件的基类。 |
PureComponent | 与 Component 类似,但自带 shouldComponentUpdate 浅比较实现。 |
createRef | 创建 ref 对象,类组件中用于访问 DOM 元素。 |
| API | 说明 |
|---|---|
createPortal | 允许将子组件渲染到 DOM 树中父组件 DOM 层次之外的不同位置,常用于模态框、全局提示等。 |
flushSync | 强制 React 同步执行状态更新并立即刷新 DOM。 |
这些 API 用于预加载脚本、样式表、字体等资源,从而让应用更快。基于 React 的框架通常会自动处理资源加载。
| API | 说明 |
|---|---|
prefetchDNS | 预解析 DNS 域名,提前获取 IP 地址,减少后续请求的 DNS 查询时间。 |
preconnect | 提前连接到预计请求资源的服务器,建立 TCP 连接和 TLS 握手,即使尚不确定具体需要哪些资源。 |
preload | 预获取并缓存预计要使用的资源(如样式表、字体、图片、外部脚本),但不执行,可节省时间。 |
preloadModule | 预获取预计要使用的 ESM 模块,但不执行。 |
preinit | 预获取并执行外部脚本,或预获取并插入样式表。 |
preinitModule | 预获取并执行一个 ESM 模块。 |
| API | 说明 |
|---|---|
createPortal | 允许将子组件渲染到 DOM 树中父组件 DOM 层次之外的不同位置,常用于模态框、全局提示等。 |
flushSync | 强制 React 同步执行状态更新并立即刷新 DOM。 |
React Router v6 完全利用 Hooks 重构。
| 组件 | 作用 |
|---|---|
BrowserRouter | history 模式路由容器 |
HashRouter | hash 模式路由容器 |
Routes / Route | 定义路由规则 |
Link / NavLink | 声明式导航 |
Outlet | 嵌套路由占位符 |
| Hook | 作用 |
|---|---|
useParams | 获取路由参数 |
useLocation | 获取当前 location 对象 |
useNavigate | 程序化导航 |
useRoutes | 配置式路由(替代 Routes + Route) |
| API | 说明 |
|---|---|
<Provider store> | 顶层组件,使 store 对下层组件可用。 |
connect(mapStateToProps, mapDispatchToProps, mergeProps, options) | 高阶组件(HOC),将 store 中的 state 和 dispatch 映射到组件的 props。 |
useSelector(selector) | Hook,从 store 中提取数据,当数据变化时强制组件重新渲染。 |
useDispatch() | Hook,返回 store 的 dispatch 函数。 |
useStore() | Hook,返回 store 实例本身(不常用)。 |
| API | 作用 | 一句话说明 |
|---|---|---|
configureStore | 创建 store | 像 createStore 但更智能,自动加 thunk 和 DevTools |
createSlice | 同时生成 reducer 和 action creators | 传入 name、initialState、reducers 对象,自动生成 |
createAsyncThunk | 处理异步 action | 自动生成 pending/fulfilled/rejected 三个 action,并在 extraReducers 中处理 |
// store.js
import { configureStore, createSlice, createAsyncThunk } from '@reduxjs/toolkit';
// 1. 同步 slice
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => { state.value += 1 }, // 直接“修改”
decrement: state => { state.value -= 1 },
incrementByAmount: (state, action) => { state.value += action.payload }
}
});
// 2. 异步 thunk
export const fetchUser = createAsyncThunk('user/fetch', async (userId) => {
const res = await fetch(`/api/user/${userId}`);
return res.json();
});
// 3. 异步 slice (处理 thunk 的三种状态)
const userSlice = createSlice({
name: 'user',
initialState: { data: null, loading: false, error: null },
reducers: {},
extraReducers: (builder) => {
builder
.addCase(fetchUser.pending, (state) => { state.loading = true })
.addCase(fetchUser.fulfilled, (state, action) => {
state.loading = false;
state.data = action.payload;
})
.addCase(fetchUser.rejected, (state, action) => {
state.loading = false;
state.error = action.error.message;
});
}
});
// 导出 action creators 和 reducer
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
const store = configureStore({
reducer: {
counter: counterSlice.reducer,
user: userSlice.reducer
}
});
export default store;
| Hook | 作用 | 类比 |
|---|---|---|
useSelector | 从 store 中读取数据 | 类似 mapStateToProps |
useDispatch | 拿到 dispatch 函数 | 类似 mapDispatchToProps |
1. 顶层用 Provider 包裹
// main.jsx
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>
);
2. 组件内读取和派发
// Counter.jsx
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from './store';
function Counter() {
// 读取状态
const count = useSelector(state => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<span>{count}</span>
<button onClick={() => dispatch(increment())}>+1</button>
<button onClick={() => dispatch(decrement())}>-1</button>
<button onClick={() => dispatch(incrementByAmount(5))}>+5</button>
</div>
);
}
3. 异步 thunk 的派发
import { fetchUser } from './store';
function UserProfile({ userId }) {
const dispatch = useDispatch();
const { data, loading, error } = useSelector(state => state.user);
useEffect(() => {
dispatch(fetchUser(userId));
}, [userId]);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return <div>{data?.name}</div>;
}
虚拟 DOM 是用 JS 对象描述真实 DOM 结构。
好处:
核心策略:
为什么 key 不能用 index?
数组增删前置元素会导致 index 错乱,引发组件状态错位、DOM 复用错误。应使用唯一稳定的业务 id。
解决旧 React 一次性渲染卡死主线程的问题。
两个阶段:
触发 setState → 生成更新任务 → Fiber 调和(可中断)→ 收集 DOM 变更 → Commit 一次性渲染 → 浏览器绘制
React 自己实现了一套事件系统(事件委托到 root 节点),性能高,与原生事件混用时,原生先执行 → 合成后执行,阻止冒泡互不生效。