useEffect
- 用于处理函数组件中的副作用
副作用
- ajax请求
- 计时器
- 更改真实的DOM
- 本地存储
- 其它会对外部产生影响的操作
- 类组件中使用副作用的生命周期
- componentDidUpdate、componentDidUpdate、componentWillMount
- useEffect:
- 本质是一个函数
- 该函数接受一个函数作为参数,接收的函数就是需要进行副作用的函数
import React, { useEffect, useState } from 'react'
function EffectHook() {
const [n, setN] = useState(0)
useEffect(() => {
console.log('这里的是副作用函数')
document.title = `计数: ${n}`
})
return (
<div>
<h2>{ n }</h2>
<button onClick={() => {
setN(n + 1)
}} >+1</button>
</div>
)
}
export default EffectHook
细节
- 副作用函数的运行时间,是在页面完成真实的UI渲染后.因此它的执行方式是异步的,不会阻塞浏览器
- 与 componentDidUpdate、componentDidUpdate区别
- 2.1 这2个更改了真实DOM,但是用户还没看到UI更新,同步的
- 2.2 useEffect中的副作用函数,更改了真实的DOM,并且用户已经看到了UI更新,异步的
- 没个函数组件中可以多次使用useEffect,但是不要放入判断或者循环的代码块中
- useEffect中的副作用函数,可以有返回值,返回值必须是一个函数,(该函数叫做清理函数)
-
- 该函数运行时间点,在每次运行副作用函数之前
-
- 首次渲染不会运行
-
- 组件销毁时候一定会运行
-
- useEffect可以传第二个参数
-
- 第二个参数是一个数组
-
- 数组中记录副作用的依赖数据
-
- 当组件重新渲染后,只有依赖数据与上一次不一样是才会执行副作用
-
- 所以,当传递了依赖数据之后,如果数据没发生变化
- 副作用函数仅在第一次渲染后运行
- 清理函数仅在卸载组件后执行
-
- 仅挂载执行一次,仅卸载时候执行一次
- useEffect(() => {...}, [])
-
例子移动的块
import React, { useEffect, useState } from 'react'
let ref = React.createRef(null)
let timer = null
/**
* 一个移动块
* @param {*} props
* left: 移动到的横坐标点
* top: 移动到的纵坐标点
* @returns
*/
function MovableBlock(props) {
useEffect(() => {
clearInterval(timer);
const div = ref.current;
let curTime = 0;//移动的总次数
const disX = props.left / 100;// 横坐标每次中移动的距离
const disY = props.top / 100; // 纵坐标每次中移动的距离
// 控制移动
timer = setInterval(() => {
curTime++;
const newLeft = curTime * disX;
const newTop = curTime * disY;
div.style.left = `${newLeft}px`
div.style.top = `${newTop}px`
if (curTime === 100) {
clearInterval(timer);
}
}, 100)
// => 清理函数
return () => {
console.log('清理函数触发');
clearInterval(timer);
}
})
return (
<div ref={ref} style={{
width: '100px',
height: '100px',
position: 'fixed',
background: '#f40'
}}></div>
)
}
function EffectHook() {
const [point, setPoint] = useState({
x: 0,
y: 0
})
const [visible, setVisible] = useState(true)
return (
<div>
{
visible && (
<div style={{
position: 'fixed',
left: 200
}}>
x: <input type="number" value={point.x} onChange={(e) => {
setPoint({
...point,
x: e.target.value
})
}} />
<br />
y: <input type="number" value={point.y} onChange={(e) => {
setPoint({
...point,
y: e.target.value
})
}} />
<MovableBlock left={point.x} top={point.y}></MovableBlock>
</div>
)
}
<button onClick={() => {
setVisible(!visible)
}}>显示/隐藏</button>
</div>
)
}
export default EffectHook
定时器案例
import React, { useEffect, useState } from 'react'
function EffectHook() {
const [n, setN] = useState(10)
useEffect(() => {
if (n === 0) return
// => 某一次渲染完成后,需要更据当前n的值,1秒后重新渲染
setTimeout(() => {
setN(n - 1)
}, 1000)
}, [n])
return (
<div>
<span>{n}</span>
</div>
)
}
export default EffectHook