当前位置: 首页 > news >正文

【React】useMemo 和 useEffect 的用法

两者的核心区别在于“何时执行、做什么、返回什么

作用

useMemo:在渲染期间计算并缓存一个“值”。目的是避免重复的昂贵计算或保持引用稳定(对象/数组/派生结果)。
useEffect:在渲染提交到 DOM 之后执行“副作用”。目的是与外部世界交互或处理需要在渲染后进行的事情(订阅、请求、操作 DOM、日志等)。

执行时机

useMemo:在组件渲染过程中同步运行计算(不触发浏览器绘制前就算完),返回值直接用于本次渲染。
useEffect:在浏览器完成绘制后异步运行(非阻塞渲染)。不会影响本次渲染的输出,只在提交后执行。

返回值

useMemo:返回计算结果(任何值:对象、数组、数字、函数等)。
useEffect:不返回值给渲染;可以返回一个清理函数用于卸载或依赖变化时清理副作用。

依赖变化时的行为

useMemo:依赖不变则复用上次结果;依赖变则在下一次渲染时重新计算值。
useEffect:依赖不变则不重新执行;依赖变则在提交后执行清理函数(若有)然后再运行副作用。

适用场景

useMemo:
重计算优化(过滤、排序、派生数据)。
保持引用稳定,避免把“每次都新建的对象/数组”传给子组件导致不必要渲染。
useEffect:
发起网络请求、订阅/取消订阅、事件监听、操作 DOM、计时器、日志、与外部存储交互等“副作用”。

常见误用对比

不要用 useEffect 去“计算一个值再 setState”来参与同一轮渲染,这会导致额外渲染;应使用 useMemo 在渲染期间直接算出值。
不要用 useMemo 做副作用(如请求、打印日志、修改外部变量);useMemo 仅用于纯计算,不能产生副作用。

与性能相关

useMemo 自身有开销,只有当计算成本高或引用稳定性能明显减少渲染时再用。
useEffect 异步执行,不阻塞渲染,但如果依赖频繁变化且在 Effect 中做重活,也会造成抖动或资源浪费。

简易判断

我只是需要一个由 props/state 派生出来的值,并且它应该在渲染时就可用且无副作用 → useMemo
我需要在组件渲染提交后与外部系统交互或安排清理 → useEffect

小例子:

useMemo:const sorted = useMemo(() => sort(items), [items])
useEffect: useEffect(() => { const id = setInterval(tick, 1000) return () => clearInterval(id) }, [])

实例直观理解

下面用两个并排对比的小例子,直观理解什么时候用 useMemo,什么时候用 useEffect + setState,以及为什么前者更合适做“纯派生计算”。

例子背景

有一份列表 allUsers,你可以通过 selectedRoles 来筛选用户。
我们在界面上展示筛选后的用户。

一、用 useEffect + setState(不太合适的做法)
说明:用 Effect 做纯计算,会导致多一次渲染;同时需要维护额外状态,容易产生同步问题。

代码片段

function Users({ allUsers, selectedRoles }) {
const [filteredUsers, setFilteredUsers] = useState(allUsers);useEffect(() => {
// 纯计算:根据依赖派生值
const next = selectedRoles.length
? allUsers.filter(u => selectedRoles.includes(u.role))
: allUsers;
setFilteredUsers(next);
}, [allUsers, selectedRoles]);return ({filteredUsers.map(u =>
{u.name} - {u.role}
)}
); }

渲染流程(关键差异)
第1步:组件渲染,filteredUsers 还是上一次的值或初始值。
第2步:提交到 DOM 后,useEffect 运行,计算 next,然后 setFilteredUsers。
第3步:因为 setState,又触发一次重新渲染,UI 才显示最新的筛选结果。
问题

多了一次渲染。
如果有多个类似派生状态,维护依赖、初始值和更新顺序更复杂。
这段逻辑并无副作用,纯粹是算值,不该放在 Effect。

二、用 useMemo(更合适的做法)
说明:在渲染期间直接计算派生值,避免额外渲染,也不需要维护额外状态。

代码片段:

function Users({ allUsers, selectedRoles }) {
const filteredUsers = useMemo(() => {
return selectedRoles.length
? allUsers.filter(u => selectedRoles.includes(u.role))
: allUsers;
}, [allUsers, selectedRoles]);return ({filteredUsers.map(u =>
{u.name} - {u.role}
)}
); }

渲染流程
第1步:组件渲染时,同步计算 filteredUsers(依赖不变则复用缓存)。
第2步:一次渲染就得到正确的 UI,不会再触发额外渲染。
结论

对于“由 props/state 派生出的值”且没有副作用,优先用 useMemo。
你的 filtered = selectedBranches… 这种就是典型的派生计算,应改为 useMemo。

三、什么时候必须用 useEffect(给你一个需要副作用的对比例子)

情景:筛选结果不仅要显示,还要同步到地址栏(URL 查询参数),或写入 localStorage。这就属于副作用,必须用 useEffect。

代码片段:

function Users({ allUsers, selectedRoles }) {
// 派生值还是用 useMemo
const filteredUsers = useMemo(() => {
return selectedRoles.length
? allUsers.filter(u => selectedRoles.includes(u.role))
: allUsers;
}, [allUsers, selectedRoles]);// 用副作用同步到外部世界(URL)
useEffect(() => {
const params = new URLSearchParams(window.location.search);
params.set('roles', selectedRoles.join(','));
const nextUrl = ${window.location.pathname}?${params.toString()};
window.history.replaceState(null, '', nextUrl);
}, [selectedRoles]);return (
{filteredUsers.map(u =>
{u.name} - {u.role}
)}
); }

要点

派生值: 用 useMemo(不产生副作用)。
与外部交互: 用 useEffect(副作用,如 URL、订阅、计时器、请求、DOM 操作)。
如果你用 useEffect 去算 filtered 再 setState,只是把纯计算绕了一圈,增加一次渲染;除非你确实需要把这个值作为“可独立修改的状态”暴露出去或做副作用,否则没必要。

四、再给一个误用示例,对比正确写法
误用:在 useEffect 里计算结果后 setState,然后这个状态只用于当前渲染。
正确:直接 useMemo 返回值,或直接在渲染里算(如果不需要缓存)。

误用:

useEffect(() => {
setFullName(${firstName} ${lastName});
}, [firstName, lastName]);

正确:

const fullName = useMemo(() => ${firstName} ${lastName}, [firstName, lastName]);
// 或者计算很轻:const fullName = ${firstName} ${lastName};

总结规则

我只是需要一个从现有数据派生出来的值、用于当前渲染 → useMemo(或直接算)。
我需要在渲染后做事(与外部交互、事件、计时、请求),或管理清理 → useEffect。
用 useEffect 做纯计算通常是不必要的,会多一次渲染。

http://www.dtcms.com/a/466246.html

相关文章:

  • 网站建设微盘下载营销型网站建设范文
  • 3.1.4. Shell 函数的知识与实践
  • 双目测距-初识
  • C++开发基础之日期处理的全面指南:从C库到Chrono
  • 北京网站维护公司直通车优化推广
  • 大厂MongoDB开发运维规范
  • 公司网站可以自己做吗wex5可以做网站吗
  • 在浏览器上播放摄像头rtsp视频流的实现方案
  • LeetCode算法日记 - Day 67: 不同路径、最长递增子序列
  • 2024ICPC区域赛香港站
  • 公司网站备案怎么做运营管理培训
  • 基于STM32的智能衣柜系统/智能衣帽间/wifi衣柜/wifi衣帽间/智能家居系统
  • access 网站后台seo引擎
  • 打字训练文章大全:哪吒打字1000篇打字文章素材
  • 使用 minimind
  • MinerU与Docling:智能文档处理框架对比
  • GAN(Generative Adversarial Nets)生成对抗网络论文笔记
  • sql练习
  • GESP C++等级认证三级12-操作string2-1
  • 人像摄影网站十大排名给公司建网站
  • 哈尔滨模板建站公司推荐上海传媒公司ceo是谁
  • Kubeadm安装完Kubernetes(K8S)后,ssh连不上了
  • 东方博宜OJ 1007:统计大写英文字母的个数 ← string
  • 3D地球可视化教程 - 第3篇:地球动画与相机控制
  • Python实现跳动的爱心
  • 网络营销策略存在的问题seo搜索引擎优化是做什么的
  • 中国建设银行门户网站wordpress 功能
  • 【ProtoBuffer】简介与安装
  • 网站管理 设置开启电子商务和网络购物网站
  • vue2和vue3响应式原理有何不同?