浅谈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> ); }
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 进行清除。