React hooks - useEffect

useEffect

用法
  1. 执行副作用操作,例如:请求数据、事件监听
    函数副作用定义:除了返回值外函数对外界环境造成的其它影响,如获取数据、修改全局变量、更新 DOM。
javascript 复制代码
useEffect(fn, deps?)

// 第一个参数 fn 是一个副作用函数,该函数会在每次渲染完成之后被调用

// 第二个参数是可选的依赖项数组,这个数组中的每一项内容都会被用来进行渲染前后的对比,依赖项发生变化时,才会重新执行副作用函数

第二个参数的用法
  1. 不指定依赖项:函数组件每次渲染完成后执行
  2. 依赖项为空数组:函数组件首次渲染完成后执行一次
  3. 依赖项为数组:函数组件每次渲染完成,对比渲染前后依赖项是否发生变化,只要变化,副作用函数就重新执行
javascript 复制代码
import React, { useEffect, useState } from 'react'

export const Counter: React.FC = () => {
  const [count, setCount] = useState(0)
  const [flag, setFlag] = useState(false)

  const add = () => {
    setCount((prev) => prev + 1)
  }

  // 在组件每次渲染完成后,如果 count 值发生了变化,则执行 effect 中的回调
  // 其它状态的变化,不会导致此回调函数的重新执行
  useEffect(() => {
    console.log(document.querySelector('h1')?.innerHTML)
  }, [count])

  return (
    <>
      <h1>count 值为:{count}</h1>
      <p>flag 的值为:{String(flag)}</p>
      <button onClick={add}>+1</button>
      <button onClick={() => setFlag((prev) => !prev)}>Toggle</button>
    </>
  )
}
清理副作用

实际应用:当前组件中使用了定时器或绑定了事件监听程序,可以在返回的函数中清除定时器或解绑监听程序

清理函数的2个触发时机:

  1. 组件被卸载的时候,会调用
  2. 当 effect 副作用函数被再次执行之前,会先执行清理函数
javascript 复制代码
useEffect(() => {
  // 1. 执行副作用操作
  // 2. 返回一个清理副作用的函数
  return () => { /* 在这里执行自己的清理操作 */ }
}, [依赖项])
组件卸载时终止未完成的 Ajax 请求

AbortController 可用于中止fetch请求

创建对象:const controller = new AbortController()

将中止信号与请求绑定:fetch( '请求路径' , { signal: controller.signal })

中止请求:controller.abort()

javascript 复制代码
const RandomColor: React.FC = () => {
  const [color, setColor] = useState('')

  useEffect(() => {
    const controller = new AbortController() 

    fetch('https://api.kaka.com/v1/color', { signal: controller.signal })
      .then((res) => res.json())
      .then((res) => {
        console.log(res)
        setColor(res.data.color)
      })
      .catch((err) => console.log('消息:' + err.message))

    // return 清理函数
    return () => controller.abort()
  }, [])

  return (
    <>
      <p>color 的颜色值是:{color}</p>
    </>
  )
} 
获取鼠标在网页中移动时的位置

如果不在组件卸载时清理定时器,下一次再显示时会再创建一个新的定时器,就会有两个定时器都打印位置

javascript 复制代码
const MouseInfo: React.FC = () => {
  // 鼠标的位置
  const [position, setPosition] = useState({ x: 0, y: 0 })

  useEffect(() => {
    // 使用setTimeout定时器,给鼠标操作添加节流操作,500s才执行一次
    let timeId : null | NodeJS.Timeout = null
    // 1. 要绑定或解绑的 mousemove 事件处理函数,MouseEvent类型
    const mouseMoveHandler = (e: MouseEvent) => {
      if(timeId !== null) return // 定时器id不为null,证明正在执行,直接return
      timeId = setTimeout(() => {
         console.log({ x: e.clientX, y: e.clientY })
         setPosition({ x: e.clientX, y: e.clientY })
         timeId = null // 为开启下一次延时器做准备
      },500)
    }

    // 2. 组件首次渲染完毕后,为 window 对象绑定 mousemove 事件
    window.addEventListener('mousemove', mouseMoveHandler)

    // 3. 返回一个清理的函数,在每次组件卸载时,为 window 对象解绑 mousemove 事件
    return () => window.removeEventListener('mousemove', mouseMoveHandler)
  }, [])

  return (
    <>
      <p>鼠标的位置:{JSON.stringify(position)}</p>
    </>
  )
}
javascript 复制代码
export const TestMouseInfo: React.FC = () => {
  // 控制子组件的显示或隐藏
  const [flag, setFlag] = useState(true)

  return (
    <>
      <h3>父组件</h3>
      {/* 点击按钮,切换 flag 的值 */}
      <button onClick={() => setFlag((prev) => !prev)}>Toggle</button>
      <hr />
      {flag && <MouseInfo />}
    </>
  )
} 
注意事项
  1. 不建议把对象作为 useEffect 的依赖项,因为 React 使用 Object.is() 来判断依赖项是否发生变化。
  2. 若未设置依赖项,不要在 useEffect 中改变依赖项的值,会造成死循环,因为状态更新都要触发useEffect。
  3. 多个不同功能的副作用尽量分开声明,不要写到一个 useEffect 中。
相关推荐
screct_demo3 小时前
詳細講一下在RN(ReactNative)中,6個比較常用的組件以及詳細的用法
javascript·react native·react.js
光头程序员11 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
limit for me11 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者11 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
VillanelleS14 小时前
React进阶之高阶组件HOC、react hooks、自定义hooks
前端·react.js·前端框架
傻小胖15 小时前
React 中hooks之useInsertionEffect用法总结
前端·javascript·react.js
flying robot1 天前
React的响应式
前端·javascript·react.js
GISer_Jing1 天前
React+AntDesign实现类似Chatgpt交互界面
前端·javascript·react.js·前端框架
智界工具库2 天前
【探索前端技术之 React Three.js—— 简单的人脸动捕与 3D 模型表情同步应用】
前端·javascript·react.js
我是前端小学生2 天前
我们应该在什么场景下使用 useMemo 和 useCallback ?
react.js