在用 Class 制作组件时,经常会用生命周期函数,来处理一些额外的事情(副作用:和函数业务主逻辑关联不大,特定时间或事件中执行的动作,比如Ajax 请求后端数据,添加登录监听和取消登录,手动修改DOM等等 ),在 React Hooks 中也需要这样类似的生命周期函数,比如在每次状态更新时执行,这就是 useEffecct。
Class 生命周期函数方式:
import React, { Component } from 'react' export default class HEffect extends Component { state = { count: 0 } componentDidMount(){ console.log(`componentDidMount:点击了${this.state.count}次`) } componentDidUpdate(){ console.log(`componentDidUpdate:点击了${this.state.count}次`) } handleClick=()=>{ this.setState({ count:this.state.count+1 }) } render() { return ( <div> <p>点击了{this.state.count}次</p> <button onClick={this.handleClick}>点击</button> </div> ) } }
用 useEffect 代替生命周期函数
import React,{useState,useEffect} from 'react' function HEffect(){ const [count,setCount] = useState(0) useEffect(()=>{ console.log(`useEffect:点击了${count}次`) }) return( <div> <p>点击了{count}次</p> <button onClick={()=>setCount(count+1)}>点击</button> </div> ) } export default HEffect;
和 Class 形式的生命周期函数完全一样,这代表第一次组件渲染和每次组件更新都会执行这个函数。
首先,我们声明了一个状态变量 count ,将它的初始值设为0,然后我们告诉 react,我们的这个组件有一个副租用,给 useEffect 传了一个匿名函数,这个匿名函数就是我们的副作用,在这里我们打印了一句话,当然也可以手动去修改一个DOM元素,当React要渲染组件时,它会记住用到的副作用,然后执行一次,等React 更新了State状态时,它再一次执行定义的副作用函数。
useEffect两个注意点:
①React首次渲染和之后的每次渲染都会调用以便 useEffect ,而之前我们要用两个生命周期函数分别表示首次渲渲染和更新导致的重新渲染
② useEffect 中定义的函数的执行不会阻碍浏览器更新视图,也就是说这些函数是异步执行的,而 componentDidMount 和 componentDidUpdate 中拿到代码都是同步执行的。
useEffect 实现 componentWillUnmount 生命周期函数
componentWillUnmount 生命周期函数,组件将要被卸载时执行,比如我们的定时器要清空,避免发生内存泄漏,比如登录状态要取消掉,避免下次进入信息出错,所以这个生命周期函数也是必不可少的。
useEffect 解绑副作用:
import React, { useState, useEffect } from 'react' import {BrowserRouter as Router,Route,Link} from 'react-router-dom' function Index(){ useEffect(() => { console.log('进入index页面') }) return <h2>这是首页</h2> } function List(){ useEffect(() => { console.log('进入list页') }) return <h2>这是列表页</h2> } function HEffect() { const [count, setCount] = useState(0) return ( <div> <p>点击了{count}次</p> <button onClick={() => setCount(count + 1)}>点击</button> <Router> <ul> <li><Link to="/">首页</Link></li> <li><Link to="/list/">列表</Link></li> </ul> <Route path="/" exact component={Index}/> <Route path="/list/" component={List}/> </Router> </div> ) } export default HEffect;
这时候,点击Link 进入首页或者列表页,都会打印出对应的一句话
这时候,可以使用返回一个函数的形式进行解绑
点击计数器按钮时,也会打印" 离开 xx 页面 “ ,这是因为,每次状态发生变化,useEffect 都进行了解绑。
要实现类似 componentWillUnmount 的效果,需要用到 useEffect 的第二个参数,它是一个数组,数组中可以写入很多状态对应的变量,意思是当状态值发生变化时,我们才进行解绑。但是当传入空数组 [ ] 时,就是当组件将被销毁时才进行解绑,这就实现了 componentDidUnmount 的生命周期函数。
import React, { useState, useEffect } from 'react' import {BrowserRouter as Router,Route,Link} from 'react-router-dom' function Index(){ useEffect(() => { console.log('进入index页面') }) return <h2>这是首页</h2> } function List(){ useEffect(() => { console.log('进入list页') }) return <h2>这是列表页</h2> } function HEffect() { const [count, setCount] = useState(0) useEffect(() => { console.log(`useEffect:点击了${count}次`) return ()=>{ console.log("执行解绑副作用函数") } },[]) return ( <div> <p>点击了{count}次</p> <button onClick={() => setCount(count + 1)}>点击</button> <Router> <ul> <li><Link to="/">首页</Link></li> <li><Link to="/list/">列表</Link></li> </ul> <Route path="/" exact component={Index}/> <Route path="/list/" component={List}/> </Router> </div> ) } export default HEffect;
并没有执行解绑副作用函数,想要每次 count 发生变化,都进行解绑副作用,需要在第二个参数的数组中加入 count 变量