Effect Hook
一、Effect Hook
Effect Hook:用于在函数组件中处理副作用
副作用:
- ajax请求
- 计时器
- 其他异步操作
- 更改真实DOM对象
- 本地存储
- 其他会对外部产生影响的操作
import React,{useState,useEffect} from 'react'
export default function App() {
const [n,setN] = useState(0);
//改变网页标题就属于副作用,所以在Effect函数中执行
useEffect(() => {
document.title=`计数器:${n}`
})
return (
<div>
<span>{n}</span>
<button onClick={()=>{
setN(n+1)
}}>+</button>
</div>
)
}
函数:useEffect,该函数接收一个函数作为参数,接收的函数就是需要进行副作用操作的函数
2、细节
- 副作用函数的运行时间点,是在页面完成真实的UI渲染之后。因此它的执行是异步的,并且不会阻塞浏览器
- 与类组件中componentDidMount和componentDidUpdate的区别
- componentDidMount和componentDidUpdate,更改了真实DOM,但是用户还没有看到UI更新,同步的。
- useEffect中的副作用函数,更改了真实DOM,并且用户已经看到了UI更新,异步的。
- 每个函数组件中,可以多次使用useEffect,但不要放入判断或循环等代码块中(同useState)。
- useEffect中的副作用函数,可以有返回值,返回值必须是一个函数,该函数叫做清理函数
- 该函数运行时间点,在每次运行副作用函数之前
- 首次渲染组件不会运行
- 组件被销毁时一定会运行
function stop() {
clearInterval(window.timer); //清空之前的计时器
window.timer = null;
}
/**
* 一个可移动的块,该组件每次渲染完成后,始终从0,0坐标在10秒钟内,移动到目标点坐标
* @param {*} props
* props.left,要移动到的目标点横坐标
* props.top,要移动到的目标点纵坐标
*/
function MovableBlock(props) {
useEffect(() => {
//渲染完成后
const div = ref.current;
let curTimes = 0; //当前移动的次数
const disX = props.left / 1000; //横坐标上每次移动的距离
const disY = props.top / 1000; //纵坐标上每次移动的距离
window.timer = setInterval(() => {
curTimes++;//移动次数+1
const newLeft = curTimes * disX;
const newTop = curTimes * disY;
div.style.left = newLeft + "px";
div.style.top = newTop + "px";
if (curTimes === 1000) {
stop();
}
}, 10)
return stop; //直接使用stop作为清理函数
})
return <div ref={ref} style={{
width: 100,
height: 100,
left: 0,
top: 0,
position: "fixed",
background: "#f40"
}}>
</div>
}
- useEffect函数,可以传递第二个参数
- 第二个参数是一个数组
- 数组中记录该副作用的依赖数据
- 当组件重新渲染后,只有依赖数据与上一次不一样的时,才会执行副作用
- 所以,当传递了依赖数据之后,如果数据没有发生变化(可以利用空数组)
- 副作用函数仅在第一次渲染后运行
- 清理函数仅在卸载组件后运行
function Test() {
useEffect(() => {
console.log("副作用函数,仅挂载时运行一次")
return () => {
console.log("清理函数,仅卸载时运行一次")
};
}, []); //使用空数组作为依赖项,则副作用函数仅在挂载的时候运行
console.log("渲染组件");
const [, forceUpdate] = useState({})
return <h1>Test组件 <button onClick={() => {
forceUpdate({})
}}>刷新组件</button></h1>
}
- 副作用函数中,如果使用了函数上下文中的变量,则由于闭包的影响,会导致副作用函数中变量不会实时变化。
import React,{useState,useEffect} from 'react'
export default function App() {
const [n,setN] = useState(0);
useEffect(() => {
setTimeout(()=>{
console.log(n);//每次渲染都会执行
},5000)
})
return (
<div>
<span>{n}</span>
<button onClick={()=>{
setN(n+1)
}}>+</button>
</div>
)
}
- 副作用函数在每次注册时,会覆盖掉之前的副作用函数,因此,尽量保持副作用函数稳定,否则控制起来会比较复杂。
博主开始运营自己的公众号啦,感兴趣的可以关注“飞羽逐星”微信公众号哦,拿起手机就能阅读感兴趣的博客啦!