对比react钩子函数
有 Vue 基础学 React 钩子会快很多。核心差别是Vue 靠「响应式系统自动追踪依赖」React 靠「钩子函数手动声明副作用和缓存」。下面用 Vue 类比把常用钩子一次讲清。一、先建立心智模型Vue Reactref / reactive useStatecomputed useMemowatch / watchEffect useEffectonMounted / onUnmounted useEffect靠依赖数组控制provide / inject useContext模板 ref useRefPinia / Vuex useReducer useContext轻量场景自定义 HookVue 3 useXxx 自定义 HookuseXxx关键区别· Vue数据变了依赖自动重新计算。· React数据变了整个函数组件重新执行你需要用钩子告诉 React「什么该缓存、什么该执行」。二、useState —— 相当于 ref / reactive作用声明一个响应式状态改变它会触发组件重新渲染。Vue 写法script setup import { ref } from vue; const count ref(0); function add() { count.value; } /script template button clickadd{{ count }}/button /templateReact 写法import { useState } from react; function Counter() { const [count, setCount] useState(0); function add() { setCount(count 1); } return button onClick{add}{count}/button; }对比Vue Reactconst count ref(0) const [count, setCount] useState(0)count.value countcount.value setCount(count 1)自动追踪依赖 手动调用 setXxx 触发更新使用场景· 计数器、表单输入、开关状态、列表数据· 任何需要「变了就刷新页面」的数据注意// ❌ 不能直接改 count; // ✅ 用 set 函数 setCount(count 1); // ✅ 依赖旧值时用函数式 setCount(prev prev 1);三、useEffect —— 相当于 watch 生命周期这是 React 最重要的钩子也是 Vue 转 React 最容易懵的。作用处理副作用请求数据、订阅事件、操作 DOM、定时器。三种形态// 1. 每次渲染都执行 useEffect(() { console.log(渲染了); }); // 2. 只在挂载时执行一次相当于 onMounted useEffect(() { console.log(挂载); }, []); // 3. 依赖变化时执行相当于 watch useEffect(() { console.log(count 变了, count); }, [count]);清理函数相当于 onUnmounteduseEffect(() { const timer setInterval(() { console.log(tick); }, 1000); // 组件卸载或依赖变化前执行 return () { clearInterval(timer); }; }, []);Vue 对比script setup import { watch, onMounted, onUnmounted } from vue; onMounted(() { console.log(挂载); }); watch(count, (newVal) { console.log(count 变了, newVal); }); onUnmounted(() { console.log(卸载); }); /scriptuseEffect(() { console.log(挂载); return () console.log(卸载); }, []); useEffect(() { console.log(count 变了, count); }, [count]);使用场景场景 写法请求接口 useEffect(() { fetchData() }, [])监听窗口大小 useEffect(() { window.addEventListener(…) }, [])定时器 useEffect(() { const t setInterval(…); return () clearInterval(t) }, [])依赖某个值变化 useEffect(() {…}, [keyword])操作 DOM useEffect(() { ref.current.focus() }, [])依赖数组规则useEffect(() {...}); // 每次渲染都跑 useEffect(() {...}, []); // 只跑一次 useEffect(() {...}, [a]); // a 变了就跑 useEffect(() {...}, [a,b]); // a 或 b 变了就跑记住依赖数组里用到的外部变量都要写进去否则拿到旧值。四、useMemo —— 相当于 computed作用缓存计算结果依赖不变就不重新计算。Vue 写法script setup import { ref, computed } from vue; const list ref([1, 2, 3]); const total computed(() { console.log(计算了); return list.value.reduce((a, b) a b, 0); }); /scriptReact 写法import { useState, useMemo } from react; function App() { const [list] useState([1, 2, 3]); const total useMemo(() { console.log(计算了); return list.reduce((a, b) a b, 0); }, [list]); return div{total}/div; }对比Vue Reactcomputed(() …) useMemo(() …, [deps])自动追踪依赖 手动写依赖数组值缓存 值缓存使用场景· 复杂计算排序、过滤、统计· 避免每次渲染都重新算· 作为其他 Hook 的依赖时保持引用稳定注意// 简单计算不用 useMemo反而增加开销 const double count * 2; // 直接算就行 // 复杂计算才用 const sorted useMemo(() bigList.sort(...), [bigList]);五、useCallback —— 缓存函数作用缓存函数引用依赖不变就返回同一个函数。为什么需要React 每次渲染都会重新创建函数如果这个函数传给子组件子组件会认为 props 变了而重新渲染。写法import { useState, useCallback } from react; function App() { const [count, setCount] useState(0); const handleClick useCallback(() { console.log(点击); }, []); return Child onClick{handleClick} /; }Vue 对比Vue 里没有直接对应因为 Vue 的响应式系统不需要你手动缓存函数。使用场景· 函数作为 props 传给 React.memo 包裹的子组件· 函数作为其他 Hook 的依赖注意// 大部分情况不需要 useCallback // 只有性能问题出现时才用useMemo 缓存值useCallback 缓存函数。// 等价 useCallback(fn, deps) useMemo(() fn, deps)六、useRef —— 相当于模板 ref 普通变量作用获取 DOM 元素像 Vue 的模板 ref保存不触发渲染的变量获取 DOMVuetemplate input refinputRef / /template script setup import { ref, onMounted } from vue; const inputRef ref(null); onMounted(() { inputRef.value.focus(); }); /scriptReactimport { useRef, useEffect } from react; function App() { const inputRef useRefHTMLInputElement(null); useEffect(() { inputRef.current?.focus(); }, []); return input ref{inputRef} /; }保存变量改了不重新渲染function App() { const countRef useRef(0); function handleClick() { countRef.current; console.log(countRef.current); // 变了但页面不刷新 } return button onClick{handleClick}点击/button; }对比Vue Reactconst el ref(null) 模板 ref“el” const el useRef(null) ref{el}el.value el.currentlet timer 普通变量 useRef 保持跨渲染使用场景· 操作 DOM聚焦、滚动、播放视频· 保存定时器 ID· 保存上一次的值· 保存不需要触发渲染的数据七、useContext —— 相当于 provide / inject作用跨层级传数据不用一层层 props 传。Vue 写法!-- 父 -- script setup import { provide } from vue; provide(theme, dark); /script !-- 深层子 -- script setup import { inject } from vue; const theme inject(theme); /scriptReact 写法import { createContext, useContext } from react; // 1. 创建 Context const ThemeContext createContext(light); // 2. 父组件提供 function App() { return ( ThemeContext.Provider valuedark Child / /ThemeContext.Provider ); } // 3. 深层子组件消费 function Child() { const theme useContext(ThemeContext); return div{theme}/div; }对比Vue Reactprovide(‘key’, value) Context.Provider value{…}inject(‘key’) useContext(Context)按 key 取 按 Context 对象取使用场景· 主题切换· 用户登录信息· 语言国际化· 全局配置八、useReducer —— 相当于简化版 Pinia作用集中管理复杂状态逻辑适合多个状态互相关联。写法import { useReducer } from react; type State { count: number }; type Action { type: add } | { type: sub } | { type: reset }; function reducer(state: State, action: Action): State { switch (action.type) { case add: return { count: state.count 1 }; case sub: return { count: state.count - 1 }; case reset: return { count: 0 }; default: return state; } } function App() { const [state, dispatch] useReducer(reducer, { count: 0 }); return ( div p{state.count}/p button onClick{() dispatch({ type: add })}1/button button onClick{() dispatch({ type: sub })}-1/button button onClick{() dispatch({ type: reset })}重置/button /div ); }对比 PiniaPinia useReducerstate stateactions dispatch(action)直接调用 action 派发 action 对象使用场景· 状态逻辑复杂多个值互相影响· 状态更新逻辑想集中管理· 配合 useContext 做轻量全局状态useState vs useReducer// 简单状态用 useState const [count, setCount] useState(0); // 复杂状态用 useReducer const [state, dispatch] useReducer(reducer, initialState);九、自定义 Hook —— 相当于 Vue 的组合式函数作用把可复用逻辑抽出来名字必须以 use 开头。Vue 写法// useCounter.tsimport{ref}fromvue;exportfunctionuseCounter(initial0){constcountref(initial);constadd()count.value;return{count,add};}React 写法// useCounter.ts import { useState } from react; export function useCounter(initial 0) { const [count, setCount] useState(initial); const add () setCount(c c 1); return { count, add }; } // 使用 function App() { const { count, add } useCounter(0); return button onClick{add}{count}/button; }使用场景· 封装请求逻辑 useRequest· 封装表单 useForm· 封装本地存储 useLocalStorage· 封装窗口大小 useWindowSize常用示例// useLocalStorage function useLocalStorageT(key: string, initial: T) { const [value, setValue] useStateT(() { const saved localStorage.getItem(key); return saved ? JSON.parse(saved) : initial; }); useEffect(() { localStorage.setItem(key, JSON.stringify(value)); }, [key, value]); return [value, setValue] as const; }十、钩子使用规则必须遵守React 钩子有两条铁律只能在函数组件或自定义 Hook 顶层调用// ❌ 不能在条件里 if (cond) { useState(0); } // ❌ 不能在循环里 for (let i 0; i 3; i) { useState(0); } // ✅ 只能在顶层 const [a] useState(0);不能在普通函数里调用// ❌ function helper() { useState(0); } // ✅ 自定义 Hook function useHelper() { useState(0); }原因React 靠调用顺序识别每个 Hook顺序乱了就出错。十一、Vue 转 React 常见误区直接改 state// ❌ count; // ✅ setCount(count 1);以为 setState 是同步的setCount(count 1); console.log(count); // 还是旧值想拿新值setCount(prev { console.log(prev 1); return prev 1; });useEffect 依赖写不全// ❌ count 是旧值 useEffect(() { console.log(count); }, []); // ✅ useEffect(() { console.log(count); }, [count]);对象/数组 state 直接改// ❌ user.name Bob; setUser(user); // ✅ 创建新对象 setUser({ ...user, name: Bob });以为 useEffect 等于 watchuseEffect 是渲染后执行不是数据一变立刻执行且它处理的是副作用不是纯计算。十二、速查表Hook Vue 对应 作用 常用场景useState ref / reactive 声明状态 计数器、表单useEffect watch 生命周期 副作用 请求、订阅、定时器useMemo computed 缓存值 复杂计算useCallback 无 缓存函数 传给子组件的函数useRef 模板 ref / 普通变量 DOM 引用 / 不渲染变量 聚焦、定时器 IDuseContext provide/inject 跨层传值 主题、用户信息useReducer Pinia 简化版 复杂状态 多状态关联自定义 Hook 组合式函数 复用逻辑 请求、表单封装十三、一句话总结· useState声明响应式数据像 ref。· useEffect处理副作用像 watch 生命周期。· useMemo缓存计算结果像 computed。· useCallback缓存函数引用。· useRef拿 DOM 或存不渲染的值。· useContext跨层传值像 provide/inject。· useReducer复杂状态管理像简化版 Pinia。· 自定义 Hook复用逻辑像 Vue 组合式函数。· 两条铁律只在顶层调用只在组件或 Hook 里调用。Vue 是「自动挡」React 是「手动挡」钩子就是你手动控制渲染和副作用的工具。

相关新闻

代码知识图谱实战:用Graphify把老系统织成一张可查询的网

代码知识图谱实战:用Graphify把老系统织成一张可查询的网

刚接手一个运营好几年的老系统时,我最先做的不是读文档,而是打开代码目录一层层往下翻,试图搞明白各个模块之间到底怎么互相调用。翻了两天还是只记得零散片段,谁依赖谁、哪个服务被谁调用,脑子里始终拼不出一张完整的…

2026/10/11 7:01:35 阅读更多 →
AI编程工具9个月实战:工作流优化ROI远超选型

AI编程工具9个月实战:工作流优化ROI远超选型

1. 从选型焦虑到流程为王:一个9个月重度使用者的真实转变用了9个月的AI编程工具之后,我最大的感受不是“哪个工具更强”,而是“怎么用”这件事,回报率远远超过了“用哪个”。这话听起来有点反直觉,毕竟过去两年&#x…

2026/10/11 7:01:35 阅读更多 →
软件测试面试20道经典题:从基础理论到项目实战全解析

软件测试面试20道经典题:从基础理论到项目实战全解析

不少朋友面试软件测试岗,其实不怕问“会不会写用例”,最怕的是面试官从一个看似简单的问题开始连续追问,比如先问“什么是软件测试”,再问“测试和调试有什么区别”,接着让你现场设计一个登录框的测试用例。这类“经典…

2026/10/11 7:01:35 阅读更多 →

最新新闻

PET口语Part 3总是卡壳?协作讨论的3个关键能力与AI陪练方案

PET口语Part 3总是卡壳?协作讨论的3个关键能力与AI陪练方案

PET口语考试中,Part 3的协作讨论环节是很多考生的难点。这部分要求两位考生围绕图片展开讨论,不仅要说清楚自己的观点,还要与搭档互动、推进话题。不少孩子阅读写作都能过关,却在Part 3卡壳,最终口语分数被拉低。PET口…

2026/10/11 7:45:59 阅读更多 →
C++学习日记 Day18:STL-拷贝替换/算术生成/集合算法

C++学习日记 Day18:STL-拷贝替换/算术生成/集合算法

## 今天学了什么今天学习C中STL-常用拷贝替换/算术生成/集合算法,并结合所学STL完成两个案例。## 常用的拷贝和替换算法copy(v1.begin(), v1.end(), v2.begin()); //拷贝replace(v.begin(), v.end(), oldValue, newValue); //替换replace_if(v.begin(), v.end()…

2026/10/11 7:45:59 阅读更多 →
小白程序员必收藏!3个黄金赛道助你年薪百万,2026春招已释放信号!

小白程序员必收藏!3个黄金赛道助你年薪百万,2026春招已释放信号!

大模型产业迎来高速发展,AI岗位需求激增,年薪百万成为可能。文章介绍了具身智能、人工智能(基础算法方向)和智能科学与技术(AIX方向)三个专业方向,分别适合动手能力强、数学功底扎实、兴趣广泛的…

2026/10/11 7:45:59 阅读更多 →
artcraft创作流程拆解:从素材准备到参数化生成的半自动实践

artcraft创作流程拆解:从素材准备到参数化生成的半自动实践

1. 从“artcraft”这个名字说起:它到底想解决什么问题第一次看到“artcraft”这个项目标题,我的直觉是:这大概率是一个把“艺术创作”和“手工实现”捏在一起的东西。拆开看,“art”指向审美、设计、视觉表达,“craft”…

2026/10/11 7:45:59 阅读更多 →
进程、资源观察与 Systemd 服务管理

进程、资源观察与 Systemd 服务管理

一、程序、进程、线程:一句话分清程序是磁盘上的可执行文件,比如 /usr/sbin/nginx,它安安静静躺在硬盘上,还没有运行,关键标识是文件路径。进程是程序的一次运行实例。程序一旦被启动,操作系统就给它一份独…

2026/10/11 7:45:59 阅读更多 →
5分钟把DeepSeek打造成代码助手:TaoToken统一Key接入VSCode与Cline

5分钟把DeepSeek打造成代码助手:TaoToken统一Key接入VSCode与Cline

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 7:44:59 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →