react 进阶hook 之 Effect Hook

简介: 在效果图中,ui是会先出现的,然后我们的title值才会从 viteApp 改成 title 0,所以可以证明 effect的执行时间点是在等ui 渲染之后再来进行执行的,并且打印我会优先effect会优先输出。也就是异步执行

Effect Hook


Effect Hook:用于在函数组件中处理副作用,类似我们类组件中的生命周期函数的,ComponentDidMount(组件刚刚挂载需要进行数据请求等副作用),ComponentDIdUpdate(组件数据已经更新并且页面已经完成挂载的对dom操作的副作用),ComponentwillUnMount(组件即将卸载销毁清楚定时器等副作用),类组件生命周期详情


语法


// 第一个请求参数是一个回调函数,用于操作副作用的,
// 第二个参数是一个数组,用于标记回调函数里面的依赖关系,react 会根据数组里面的值来进行依赖收集,从而来判断回调函数是否执行
useEffect(() => {}, [])


该hooks 也和state hooks 一样,可以在同一函数里面书写多个,实现代码逻辑的分离。便于代码的维护以及代码的可读性。 stateHooks 详见


副作用:


1.ajax请求

2.计时器

3.其他异步操作

4.更改真实DOM对象

5.本地存储

6.其他会对外部产生影响的操作


函数:useEffect,该函数接收一个函数作为参数,接收的函数就是需要进行副作用操作的函数


细节


1. 副作用函数的运行时间点


是在页面完成真实的UI渲染之后。因此它的执行是异步的


1.与类组件中componentDidMount和componentDidUpdate的区别


2.componentDidMount和componentDidUpdate,更改了真实DOM,但是用户还没有看到UI更新,同步的。


3.useEffect中的副作用函数,更改了真实DOM,并且用户已经看到了UI更新,异步的。


案例


import React, { useEffect, useState } from 'react'
export default function TestEffectHook() {
  // 计数器
  const [count, setCount] = useState(0);
  // 改变网页的title
  useEffect(() => {
    document.title = `title ${count}`;
    // 为了证明effect是异步的,我在这里直接报错,看看ui是否会先出现,然后在报错,并且网页的title有没有改变
    throw new Error('我要报错')
  })
  console.log('我会比effect优先输出')
  return (
    <div>
      <p>{count}</p>
      <button onClick={() => {
        setCount(pre => pre + 1)
      }}> + 1  </button>
    </div>
  )
}


效果


20210405170517862.gif


在效果图中,ui是会先出现的,然后我们的title值才会从 viteApp 改成 title 0,所以可以证明 effect的执行时间点是在等ui 渲染之后再来进行执行的,并且打印我会优先effect会优先输出。也就是异步执行


2. 每个函数组件中,可以多次使用useEffect,但不要放入判断或循环等代码块中。


对于这个概念,在所有的hooks 中都是同样的,可以使用多个useEffect,但是不能在判断或者循环的代码块中使用,原因是和hooks的实现原理有关,所有的hooks 会使用一个类似地图的map来及记录每一个hooks的顺序,如果顺序改变,会引起未知的错误。

详情详见


3. useEffect中的副作用函数,可以有返回值,返回值必须是一个函数,该函数叫做清理函数


1.该函数运行时间点,在每次运行副作用函数之前

2.首次渲染组件不会运行

3.组件被销毁时一定会运行


案例


import React, { useEffect, useState } from 'react'
export default function TestEffectHook() {
  // 计数器
  const [count, setCount] = useState(0);
  // 改变网页的title
  useEffect(() => {
    console.log('effect副作用函数执行');
    return () => {
      console.log('cleanup 函数执行了');
    }
  });
  // 控制组件显示隐藏
  const [canShow, setCanShow] = useState(true)
  return (
    <div>
      {canShow && (
        <div>
          <p>{count}</p>
          <button onClick={() => {
            setCount(pre => pre + 1)
          }}> + 1  </button>
        </div>
      )}
      <button onClick={() => {
        setCanShow(!canShow)
      }}>显示/隐藏</button>
    </div>
  )
}


效果


20210405174002689.gif


一切看效果,默认清除副作用函数不执行,只有在组件销毁,或者数据更新的时候,才会优先执行清理副作用函数,然后在执行副作用函数


4. useEffect函数,可以传递第二个参数


1.第二个参数是一个数组

2.数组中记录该副作用的依赖数据

3.当组件重新渲染后,只有依赖数据与上一次不一样的时,才会执行副作用

4.所以,当传递了依赖数据之后,如果数据没有发生变化

  1.副作用函数仅在第一次渲染后运行

  2.清除副作用只会在组件销毁的时候执行


案例


import React, { useEffect, useState } from 'react'
export default function TestEffectHook() {
  // 计数器
  const [count, setCount] = useState(0);
  // 改变网页的title
  useEffect(() => {
    console.log('effect副作用函数执行');
    document.title = `title ${count}`
    return () => {
      console.log('cleanup 函数执行了');
    }
  },[count]);
  return (
    <div>
        <div>
          <p>{count}</p>
          <button onClick={() => {
            setCount(pre => 10)
          }}> 只改变一次title  </button>
        </div>
    </div>
  )
}


效果


20210405180736171.gif


5. 副作用函数中,如果使用了函数上下文中的变量,则由于闭包的影响,会导致副作用函数中变量不会实时变化。


每一个effect 函数是单独指向当前依赖值的,并且执行的方式是放在执行栈中,先进先出,然后依次执行。


案例


import React, { useEffect, useState } from 'react'
export default function TestEffectHook() {
  // 计数器
  const [count, setCount] = useState(0);
  // 改变网页的title
  useEffect(() => {
    console.log('effect副作用函数执行');
    document.title = `title ${count}`
    // 每一秒后打印结果
    setTimeout(() => {
      console.log(count);    
    },2000);
    return () => {
      console.log('cleanup 函数执行了');
    }
  },[count]);
  return (
    <div>
        <div>
          <p>{count}</p>
          <button onClick={() => {
            setCount(pre => pre + 1)
          }}> + 1 </button>
        </div>
    </div>
  )
}


效果


20210405181545240.gif


从结果中,我们可以看到,我们要打印的count还没有2s就打印了,有兴趣的同学可以拿代码设置更长的时间来进行打印,会发现七九


6. 副作用函数在每次注册时,会覆盖掉之前的副作用函数。


因此,尽量保持副作用函数稳定,否则控制起来会比较复杂。这一句话啥意思呢,我们的effect里面可以接收一个函数,不到万不得已,不建议使用动态的函数哦

相关文章
|
2月前
|
前端开发
React 中的 Hook 概念
【8月更文挑战第31天】
22 0
|
3月前
|
前端开发 JavaScript 数据格式
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
63 1
|
3月前
|
前端开发
React useImperativeHandle Hook
【7月更文挑战第1天】React useImperativeHandle Hook
21 3
|
3月前
|
存储 前端开发 JavaScript
react hooks 学习进阶
【7月更文挑战第12天】 React Hooks(自16.8版起)让函数组件能处理状态和副作用。useState用于添加状态管理,useEffect处理副作用,useContext共享数据,useReducer处理复杂状态逻辑,useRef获取引用。进阶技巧涉及性能优化,如useMemo和useCallback,以及遵循规则避免在不适当位置调用Hooks。理解异步更新机制和结合Redux等库提升应用复杂性管理。持续学习新技巧是关键。
43 0
|
3月前
|
前端开发
Vue3 【仿 react 的 hook】封装 useTitle
Vue3 【仿 react 的 hook】封装 useTitle
30 0
|
3月前
|
前端开发 API
Vue3 【仿 react 的 hook】封装 useLocation
Vue3 【仿 react 的 hook】封装 useLocation
26 0
|
5月前
|
前端开发 JavaScript
【边做边学】React Hooks (二)——useEffect Hook
【边做边学】React Hooks (二)——useEffect Hook
|
5月前
|
前端开发 JavaScript
React中useEffect Hook使用纠错
React中useEffect Hook使用纠错
32 0
|
5月前
|
前端开发 中间件 数据安全/隐私保护
React路由进阶方法
React路由进阶方法
53 1
|
5月前
|
自然语言处理 前端开发 JavaScript
说说你对 React Hook的闭包陷阱的理解,有哪些解决方案?
说说你对 React Hook的闭包陷阱的理解,有哪些解决方案?
98 0