React useEffect深度解析:副作用操作详解与实战
创作时间:
作者:
@小白创作中心
React useEffect深度解析:副作用操作详解与实战
引用
CSDN
1.
https://blog.csdn.net/weixin_41192489/article/details/138706946
React中的useEffect是一个非常重要的Hook函数,用于处理组件的副作用操作。本文将详细介绍useEffect的使用场景、语法和具体应用,通过多个代码示例帮助读者深入理解其工作原理和使用方法。
什么是副作用操作?
useEffect用于编写由渲染本身引起的对接组件外部的操作(官方称呼为:副作用操作)。
以下情况会触发页面渲染:
- 初次加载页面(组件挂载)
- 响应式变量发生变化,触发页面根据新值重新渲染(组件更新)
- 关闭页面(组件卸载)
以下情况需要添加副作用操作:
- 页面初步渲染完成后,向服务器获取数据完成页面的最终渲染
- 响应式变量发生变化时,先根据新值执行必要的业务逻辑,再进行最终的页面更新渲染
- 关闭页面时,需清除副作用,如清除定时器,移除全局事件等。
useEffect语法
useEffect是一个Hook函数:
- 第一个参数(必要):自定义的处理函数(官方称呼为:副作用函数),可在副作用函数中return一个函数来清除副作用,从第二次执行副作用函数开始,每次都会先执行return中的清除副作用的函数,再执行副作用函数,当组件卸载时,所有清除副作用的函数会按顺序依次执行。
- 第二个参数(可选):依赖项(不能为对象/数组等引用类型的数据,因为引用类型的数据每次页面渲染时都会生成新地址,若useEffect的处理函数会引发页面重新渲染,则会导致死循环)
无依赖项
执行副作用函数的时机:
- 组件初次渲染后(组件挂载完成),在开发环境,会执行两次,生产环境仅执行一次
- 组件更新渲染前(任一响应式变量变化都会触发!)
import { useEffect } from "react";
function Demo() {
useEffect(() => {
console.log("执行了副作用函数");
});
return (
<>
<div>你好</div>
</>
);
}
export default Demo;
依赖项为空数组 []
类似Vue的生命周期mounted
执行副作用函数的时机:
- 组件初次渲染后(组件挂载完成),在开发环境,会执行两次,生产环境仅执行一次
import { useEffect } from "react";
function Demo() {
useEffect(() => {
console.log("执行了副作用函数");
}, []);
return (
<>
<div>你好</div>
</>
);
}
export default Demo;
使用场景:
初次渲染页面时访问接口加载页面数据
import { useEffect, useState } from "react";
import axios from "axios";
function Demo() {
const [list, setList] = useState([]);
useEffect(() => {
async function getList() {
const res = await axios.get("http://localhost:3000/dataList");
setList(res.data);
}
getList();
}, []);
return (
<>
{list.map((item) => (
<div key={item.id}>{item.title}</div>
))}
</>
);
}
export default Demo;
依赖项为响应式变量构成的数组
类似Vue的立即执行侦听器watch
执行副作用函数的时机:
- 组件初次渲染后(组件挂载完成),在开发环境,会执行两次,生产环境仅执行一次
- 响应式变量发生变化触发页面进行更新渲染前
import { useEffect, useState } from "react";
function Demo() {
const [name, setName] = useState("朝阳");
useEffect(() => {
// 在挂载和 name 更新时,都会执行!
console.log("当前name值为:", name);
}, [name]);
function changeName() {
setName("晚霞");
}
return (
<>
<button onClick={changeName}>改名字</button>
</>
);
}
export default Demo;
清除副作用
最经典的场景即在组件卸载时清除计时器,以免内存泄露
清除副作用的逻辑,写在useEffect内回调函数的return后面,需要注意的是,return后必须是一个函数!
father.jsx
import { useState } from "react";
import Child from "./child.jsx";
function Father() {
const [ifChild, setIfChild] = useState(true);
function removeChild() {
setIfChild(false);
}
return (
<>
<button onClick={removeChild}>移除子组件</button>
{ifChild && <Child />}
</>
);
}
export default Father;
child.jsx
import { useEffect } from "react";
function Child() {
useEffect(() => {
// 添加定时器
const timer = setInterval(() => {
console.log("执行了定时器");
}, 1000);
return () => {
// 清除定时器
clearInterval(timer);
};
});
return (
<>
<div>
<h1>我是子组件</h1>
</div>
</>
);
}
export default Child;
如何关闭开发环境执行两次?
将src/main.jsx中的<React.StrictMode> </React.StrictMode>标签删除即可。
useEffect演示代码
可通过下方演示代码,在控制台监听查看父子组件副作用函数和清除副作用函数的执行顺序和时机
father.jsx
import { useEffect, useState } from "react";
import Child from "./Child.jsx";
export default function Father() {
const [showChild, setShowChild] = useState(true);
const [num, setNum] = useState(0);
console.log("父组件渲染");
useEffect(() => {
console.log("执行了父组件依赖[]的useEffect内的代码");
return () => {
console.log("执行了父组件依赖[]的useEffect中return的函数");
};
}, []);
return (
<div style={{ border: "1px solid", padding: "10px", margin: "10px" }}>
<h1>父组件</h1>
<p>num为:{num}</p>
<button
onClick={() => {
setNum(num + 1);
}}
>
+1
</button>
{showChild && <Child />}
<button
onClick={() => {
setShowChild(false);
}}
>
卸载子组件
</button>
<button
onClick={() => {
setShowChild(true);
}}
>
挂载子组件
</button>
</div>
);
}
Child.jsx
import { useEffect, useState } from "react";
function Child() {
const [name, setName] = useState("朝阳");
console.log("子组件渲染");
useEffect(() => {
console.log("执行了子组件无依赖的useEffect内的代码");
return () => {
console.log("执行了子组件无依赖的useEffect中return的函数");
};
});
useEffect(() => {
console.log("执行了子组件依赖 [] 的useEffect内的代码");
return () => {
console.log("执行了子组件依赖 [] 的useEffect中return的函数");
};
}, []);
useEffect(() => {
console.log("执行了子组件中依赖name的useEffect内的代码");
return () => {
console.log("执行了子组件中依赖name的useEffect中return的函数");
};
}, [name]);
return (
<div style={{ border: "1px solid", padding: "10px", margin: "10px" }}>
<h1>子组件</h1>
<p>名称为:{name}</p>
<button onClick={() => setName("张三")}>改名称</button>
</div>
);
}
export default Child;
热门推荐
长安汽车冬季保养指南:从机油到电池,这些细节不容忽视
新手司机必看:长安汽车自动挡驾驶秘籍
《阿房宫赋》教学新思路:从创新方法到文学赏析
杜牧《阿房宫赋》:经典散文的永恒魅力
揭秘阿房宫:从杜牧的文学想象到考古真相
杜牧笔下的阿房宫:建筑奇迹与历史警示
犹太复国主义与以色列建国的复杂关系揭秘
辛弃疾《清平乐·村居》:一首词的现代演绎与文化传承
辛弃疾的田园生活:从壮志难酬到心灵归宿
从心理学角度看失望:原因及对策探讨
7首古诗词,写尽人间旧恨新愁
黄梅戏为何与安庆结下不解之缘?
京剧、越剧、黄梅戏、评剧……世界戏剧日带你走进戏曲世界
女驸马故事的原型:历史与传说的交织
难怪王扶林导演非要把她“化丑”,当年的她漂亮到欧阳奋强不敢看
“世界非遗”粤剧壮乡焕新生 新潮演绎走向东盟
手指关节疼痛的五大原因及科学应对方案
滑屏太多当心手指病,从弹响指到关节炎的预防指南
甲沟炎居家治疗与预防:五步远离“十指连心”之痛
虚拟现实辅助工程技术在航空培训中的作用
游戏技术赋能大健康,想象空间有多大?
鹤岗中医药展厅设计方案:融合传统与科技的智慧体验空间
领导升职跟你告别,一句恭喜领导高升暴露低情商,高情商这样回复
糖尿病防治有了新方案:2030年要实现“两率”60%和70%
红枣苹果汤真的能增强免疫力吗?
研究证实:适度饥饿疗法对6类疾病有改善作用
出国留学、夏令营可以携带哪些药品?能携带多少?
国际行李托运流程是怎样的?(国际行李托运流程介绍)
间歇性禁食助治8种疾病,从糖尿病到心理障碍
中药可带上飞机吗?