浅谈hooks——useEffect

react 16.8发布以来,函数式写法逐渐取代class的写法,在react函数式写法中,最重要是就是react所推出的新特性:hook,今天就来简单谈谈最基础的hook——useEffect

在react的类时代,人们最关心的便是类中生命周期方法,你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount(组件挂载即被执行)componentDidUpdate(组件更新执行) 和 componentWillUnmount(组件卸载执行) 这三个函数的组合

那针对这三种方法,我们便来看看useEffect是如何使用的

在此贴上官方最经典的案例

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

由上述代码可知,我们在函数中使用hook,当组件进行挂载,更新,以及卸载时,都会执行一遍useEffect中的方法,在某些class的场景中会遇到生命周期写相同的方法,这在代码优雅性显得没那么好看,而在新推出的hook方法中,只需要一个hook即可处理相同生命周期的方法,这样子的代码是否更好看些了呢?

在官方的代码中,我们执行后便会发现,当组件进行挂载,更新,以及卸载时都会执行一遍方法,那么我们如何控制他们呢?尤其在组件更新时,我们肯定是不想在必要的更新中执行非必要的代码

hook提供了两种方法供我们控制不同的时间段执行的代码

useEffect'提供两种入参,第一个入参:函数 第二个入参:数据(可选)

入参一即hook中处理的方法,入参二就是控制hook的执行的变量了

如何与组件挂载,更新,卸载联系呢?

组件挂载:即入参一的函数执行

组件更新:即入参二的数据监听

组件卸载:即入参一的函数返回

直接贴出代码

组件挂载我们不用多说,当你写出useEffect时,无论如何,在组件挂载时都会执行,所以我们着重讲下组件的更新及卸载import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
   return ()=>{
    console.log("组件卸载")
  } }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }

组件卸载:将上面代码进行修改,你只需知道,我们传入函数到react中的时候,既然是函数,自然有返回值,当你返回一个函数时,你所返回的函数就会在卸载时执行,当你进行点击时,你会发现,日志中一直打印组件卸载,这其实是因为effect 发生在“渲染之后”这种概念,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。

function Example() {
  const [count, setCount] = useState(0);
 const [change,setChange] = useState(false) useEffect(()
=> { document.title = `You clicked ${count} times`;    return ()=>{     console.log("组件卸载")   } },[change]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button>
    <button onClick={()=>setChange(!change)}>
     change Click 
     </button> </div> ); }
 依旧是上述代码,我们在useEffect第二个参数传入一个数组,该数组中传入change变量,那么当change发生改变时,useEffect就会重新渲染执行
function Example() {
  const [count, setCount] = useState(0);
 const [change,setChange] = useState(false) 

  useEffect(() => {
    document.title = `You clicked ${count} times`;
   return ()=>{
    console.log("组件卸载")
  }
  },[]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    <button onClick={()=>setChange(!change)}>
     change Click 
     </button>
    </div>
  );
}

当我们传入空数组时,那么useEffect在组件的生命周期中就只会执行一次

至此useEffect的基础使用就已经阐述完毕,但在实际的使用中,我们会遇到许多问题,下面就提出我遇到的一个问题,也是促使我写此博客的缘由

看下如下代码

function Example() {
  const [count, setCount] = useState(0);
 const [change,setChange] = useState(false) 

  useEffect(() => {
    document.title = `You clicked ${count} times`;
   return ()=>{
    console.log("组件卸载")    
            console.log('只执行一次的hook',change)
  }
  },[]);

useEffect(() => {
    document.title = `You clicked ${count} times`;
   return ()=>{
    console.log("组件卸载")    
            console.log(change)
  }
  },[change]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
  <button onClick={()=>setChange(!change)}>
   change Click 
  </button>
    </div>
  );
}

在上述代码中,我们写了两个useEffect,一个有change的监听,一个只执行一遍,我们都在卸载时打印change的值,会发现有监听的hook,在监听的变量发生改变时就会打印改变前的变量,无监听则会在组件卸载时执行一次,effect原理其实可以理解成,在组件挂载时就会将数据记录,当卸载hook时执行的方法,只会取到挂载时的变量,无法拿到最新的变量。因此若hook只执行一次,我们就不应当在hook卸载的方法中,去获取最新的数据,因为这是获取不到的

传递给 useEffect 的函数在每次渲染中都会有所不同,这是刻意为之的。事实上这正是我们可以在 effect 中获取最新的 count 的值,而不用担心其过期的原因。每次我们重新渲染,都会生成新的 effect,替换掉之前的。

React 何时清除 effect? React 会在组件卸载的时候执行清除操作。正如之前学到的,effect 在每次渲染的时候都会执行。这就是为什么 React 在执行当前 effect 之前对上一个 effect 进行清除。

 

posted @ 2022-04-29 10:22  迷失哥哥  阅读(223)  评论(0编辑  收藏  举报