跳到正文

Vue 组合式函数与 React 对比 ​

  • 状态:未准备
  • 适用方向:前端 / Go 全栈
  • 最近复习:待填写
  • 下次复习:待安排

一句话回答 ​

Vue composable 用函数封装响应式状态及其副作用,默认每次调用拥有独立状态;与 React Hook 相似的是复用有状态逻辑,依赖追踪和执行模型则不同。

原理解释 ​

Composition API 解决什么? ​

Options API 按 data、methods、computed、生命周期等选项组织代码;Composition API 可以把同一业务的状态、计算与清理聚在一起,更便于提取复用。它不是强制把所有逻辑写在一个超长 setup 中,也不意味着 Options API 不可用。

可复用逻辑怎样封装? ​

ts
import { ref, onMounted, onUnmounted } from 'vue'

export function useWindowWidth() {
  const width = ref<number | null>(null)
  function update() { width.value = window.innerWidth }
  onMounted(() => {
    update()
    window.addEventListener('resize', update)
  })
  onUnmounted(() => window.removeEventListener('resize', update))
  return { width }
}

返回包含 ref 的普通对象,调用方 const { width } = useWindowWidth() 可保留响应式。width 初始为 null,让挂载前状态明确,并避免模块或 setup 顶层直接读取 window。这里仍约定在组件 setup 中同步调用,以注册生命周期。

与 React Hook 的对比 ​

维度Vue Composition APIReact 函数组件 / Hooks
组件主体setup 通常每个实例初始化一次,渲染函数可多次执行组件函数随渲染再次调用
状态读取ref/代理属性追踪依赖本次渲染获得状态快照
更新表达可通过 ref/代理修改,触发关联订阅使用 setter/dispatch 等请求更新,通常不可变处理对象
派生值computed 自动追踪 getter 内读取常直接计算,必要时用 useMemo 显式依赖
外部同步watch/watchEffect、生命周期useEffect/useLayoutEffect 等
共享逻辑composable 默认独立状态自定义 Hook 默认独立状态

Vue 也有普通 JavaScript 闭包,可能因提前取值、异步竞态或不恰当解构而读取旧数据,不能说“Vue 完全没有闭包问题”。React 的 ref 则可保存跨渲染可变值,不能把两边差异简化为一方只能使用快照。

场景与边界 ​

composable 适合媒体会话、监听、请求等跨组件复用的逻辑;纯工具函数不需要强行包装成 useXxx。把状态放到模块顶层会改成共享状态,还要考虑 SSR 请求间隔离;复杂共享业务可用 Pinia。参数既可能是值、ref 或 getter 时,可设计为 MaybeRefOrGetter 并在响应式副作用内使用 toValue(Vue 3.3+)读取,避免仅在入口求值一次。

项目中的应用 ​

对照 SimulSpeak 的 useSession 思考 Vue 迁移:哪些资源放在闭包里,哪些状态暴露为 ref,停止与卸载如何复用清理。这里是设计练习,仓库尚无 Vue 迁移实现。

常见追问 ​

  • 比 mixin 好在哪里? 依赖与返回值更显式,来源和命名冲突更易管理,便于类型推导与组合。
  • 两个组件调用同一个 composable 会共享状态吗? 若状态在函数内部创建,默认不共享;模块变量或外部 store 则可能共享。
  • 能把 useEffect 逐行换成 watchEffect 吗? 不宜,先明确依赖、清理、DOM 时机和是否应由用户事件触发。

参考资料 ​

理解机制,讲清取舍,用复盘检验掌握。