Effect Hook:用于在函数组件中处理副作用

对于HOOK,要忘记生命周期和类组件那一套!!

副作用:

  1. ajax请求
  2. 计时器
  3. 其他异步操作
  4. 更改真实DOM对象
  5. 本地存储
  6. 其他会对外部产生影响的操作

useEffect的用法

  1. 该函数的第一个参数,就是一个带有 副作用操作的函数
  2. 第二个参数,就是副作用函数的依赖项数组 ```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在一段时间内移动到目标点坐标

  1. * @
  2. */

function MovableBlock(props) { useEffect(()=>{ //副作用操作 const div = ref.current; let curNumber = 0;//当前移动次数 const disX = props.left / 1000;//每次要移动的距离 const disY = props.top / 1000;

  1. window.timer = setInterval(() => {
  2. curNumber++;
  3. const newLeft = curNumber * disX;
  4. const newTop = curNumber * disY;
  5. div.style.left = newLeft + "px";
  6. div.style.top = newTop + "px";
  7. if(curNumber===100){
  8. stop();
  9. }
  10. }, 10);
  11. return ()=>{
  12. stop();
  13. }
  14. }, [props.left, props.top]);
  15. return (
  16. <div ref={ref} style={{
  17. width: 100,
  18. height: 100,
  19. left: 0,
  20. top: 0,
  21. position: "fixed",
  22. background: "#f40",
  23. }}>
  24. </div>
  25. )

}

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();

  1. return (
  2. <div style={{
  3. paddingTop: 200,
  4. }}>
  5. {
  6. visible && (
  7. <div>
  8. {/* (
  9. //display: 'none';元素dom结构还是存在的
  10. <div style={{display: visible?'block':'none'}}> */}
  11. {/* 下述是受控组件, 非受控组件需要再加个确定按钮,一点击就setPoint */}
  12. x: <input type="number" value={point.x} onChange={e=>{
  13. setPoint({
  14. ...point,
  15. x: parseInt(e.target.value)
  16. })
  17. }} />
  18. y: <input type="number" value={point.y} onChange={e=>{
  19. setPoint({
  20. ...point,
  21. y: parseInt(e.target.value)
  22. })
  23. }} />
  24. <MovableBlock left={point.x} top={point.y} />
  25. </div>
  26. )
  27. }
  28. <button onClick={e=>{
  29. setVisible(!visible);
  30. }}>显示/隐藏</button>
  31. </div>
  32. )

}

```

细节:

  1. 副作用函数的运行时间点,是在页面完成真实的UI渲染之后。因此它的执行是异步的,不会阻塞浏览器
  2. 类似类组件中componentDidMount、componentDidUpdate、componentWillUnmount,但有区别
    1. componentDidMount和componentDidUpdate,真实DOM已经更改,但是用户还没有看到UI更新,同步的。因为js主线程和ui线程互斥
    2. useEffect中的副作用函数,真实DOM已经更改,并且用户已经看到了UI更新,异步的
  3. 每个函数组件中,可以多次使用useEffect,同样的,不能放在循环、判断中
  4. useEffect中的副作用函数,可以有返回值,返回值必须是一个函数,该函数叫做清理函数
    1. 清理函数的 运行时机 是 每次运行副作用函数之前
    2. 首次渲染组件不会运行
    3. 组件被销毁时一定会运行
  5. useEffect函数,可以传递第二个参数
    1. 第二个参数是一个数组
    2. 数组中记录该副作用的依赖数据
    3. 当组件重新渲染后,只有依赖数据与上一次不一样时,才会执行副作用函数
    4. 所以当传递了依赖数据后,如果数据没有发生变化(浅比较)
      1. 副作用函数仅在第一次渲染后运行
      2. 清理函数仅在卸载组件后运行
    5. 使用空数组作为依赖项,则副作用函数仅在组件挂载后 运行一次
  6. 副作用函数中,如果使用了函数上下文中的变量,则由于闭包的影响(准确说是由于State机制的问题,它每次都是捕获指定UI的环境),会导致副作用函数中变量不会实时化
  7. 副作用函数在每次注册时,会覆盖掉之前的副作用函数,因此,尽量保持副作用函数是稳定的,否则控制起来会比较负责。

特别注意:
image.png这是错的,这只会疯狂打印9
image.png这才是对的,每秒递减一个数

不要玩这种怪异的玩意儿(在函数里判断不行吗,非要判断成两个不同的函数):
image.png
image.png
运行结果为:
image.png
odd 副作用函数。点击。—odd 清理函数,even 副作用函数。点击— even 清理函数, odd 副作用函数