对于HOOK,要忘记生命周期和类组件那一套!!
副作用:
- ajax请求
- 计时器
- 其他异步操作
- 更改真实DOM对象
- 本地存储
- 其他会对外部产生影响的操作
useEffect的用法
- 该函数的第一个参数,就是一个带有 副作用操作的函数
- 第二个参数,就是副作用函数的依赖项数组 ```jsx import React, { useState, useEffect} from ‘react’
window.timer = null; const ref = React.createRef();//保存想要引用的DOM
function stop(){ clearInterval(window.timer); window.timer = null; } /* 一个可以动的块,该组件每次渲染完成后,始终从0,0在一段时间内移动到目标点坐标
* @
*/
function MovableBlock(props) { useEffect(()=>{ //副作用操作 const div = ref.current; let curNumber = 0;//当前移动次数 const disX = props.left / 1000;//每次要移动的距离 const disY = props.top / 1000;
window.timer = setInterval(() => {
curNumber++;
const newLeft = curNumber * disX;
const newTop = curNumber * disY;
div.style.left = newLeft + "px";
div.style.top = newTop + "px";
if(curNumber===100){
stop();
}
}, 10);
return ()=>{
stop();
}
}, [props.left, props.top]);
return (
<div ref={ref} style={{
width: 100,
height: 100,
left: 0,
top: 0,
position: "fixed",
background: "#f40",
}}>
</div>
)
}
export default function LearState1() { const [visible, setVisible] = useState(true); const [point, setPoint] = useState({x: 0, y:0}); // const txtX = React.createRef(); // const txtY = React.createRef();
return (
<div style={{
paddingTop: 200,
}}>
{
visible && (
<div>
{/* (
//display: 'none';元素dom结构还是存在的
<div style={{display: visible?'block':'none'}}> */}
{/* 下述是受控组件, 非受控组件需要再加个确定按钮,一点击就setPoint */}
x: <input type="number" value={point.x} onChange={e=>{
setPoint({
...point,
x: parseInt(e.target.value)
})
}} />
y: <input type="number" value={point.y} onChange={e=>{
setPoint({
...point,
y: parseInt(e.target.value)
})
}} />
<MovableBlock left={point.x} top={point.y} />
</div>
)
}
<button onClick={e=>{
setVisible(!visible);
}}>显示/隐藏</button>
</div>
)
}
细节:
- 副作用函数的运行时间点,是在页面完成真实的UI渲染之后。因此它的执行是异步的,不会阻塞浏览器
- 类似类组件中componentDidMount、componentDidUpdate、componentWillUnmount,但有区别
- componentDidMount和componentDidUpdate,真实DOM已经更改,但是用户还没有看到UI更新,同步的。因为js主线程和ui线程互斥
- useEffect中的副作用函数,真实DOM已经更改,并且用户已经看到了UI更新,异步的。
- 每个函数组件中,可以多次使用useEffect,同样的,不能放在循环、判断中
- useEffect中的副作用函数,可以有返回值,返回值必须是一个函数,该函数叫做清理函数
- 清理函数的 运行时机 是 每次运行副作用函数之前
- 首次渲染组件不会运行
- 组件被销毁时一定会运行
- useEffect函数,可以传递第二个参数
- 第二个参数是一个数组
- 数组中记录该副作用的依赖数据
- 当组件重新渲染后,只有依赖数据与上一次不一样时,才会执行副作用函数
- 所以当传递了依赖数据后,如果数据没有发生变化(浅比较)
- 副作用函数仅在第一次渲染后运行
- 清理函数仅在卸载组件后运行
- 使用空数组作为依赖项,则副作用函数仅在组件挂载后 运行一次
- 副作用函数中,如果使用了函数上下文中的变量,则由于闭包的影响(准确说是由于State机制的问题,它每次都是捕获指定UI的环境),会导致副作用函数中变量不会实时化
- 副作用函数在每次注册时,会覆盖掉之前的副作用函数,因此,尽量保持副作用函数是稳定的,否则控制起来会比较负责。
特别注意:
这是错的,这只会疯狂打印9
这才是对的,每秒递减一个数
不要玩这种怪异的玩意儿(在函数里判断不行吗,非要判断成两个不同的函数):
运行结果为:
odd 副作用函数。点击。—odd 清理函数,even 副作用函数。点击— even 清理函数, odd 副作用函数