用 useEffect 模拟组件生命周期
useEffect
让函数组件模拟生命周期
- 默认函数组件没有生命周期
- 函数组件是一个纯函数,执行完后即销毁,自己无法实现生命周期
- 使用 Effect Hook 把生命周期 “钩” 到纯函数中
例子
import React, {useState, useEffect} from "react";
function LifeCycles() {
const [count, setCount] = useState(0)
const [name, setName] = useState('lzw.')
// 模拟 class 组件的 DidMount 和 DidUpdate
// useEffect(() => {
// console.log('此处发送一个 Ajax 请求')
// })
// 模拟 class 组件的 DidMount
useEffect(() => {
console.log('加载完了')
}, []) // 第二个参数是 [] (不依赖任何 state)
// 模拟 class 组件的 DidUpdate
useEffect(() => {
console.log('更新了')
}, [count, name]) // 第二个参数是依赖的 state
// 模拟 class 组件的 DidMount
useEffect(() => {
// let timerId = setInterval(() => {
// console.log(Date.now())
// }, 1000)
// 返回函数
// 模拟 class 组件的 WillUnMount
return () => {
clearInterval(timerId)
}
}, [])
function setVal() {
setCount(count + 1)
setName(name + '-' + count)
}
return <div>
<p>你点击了多少次 {count} 次 {name}</p>
<button onClick={setVal}>点击</button>
</div>
}
export default LifeCycles
useEffect 使用总结
- 模拟 componentDidMount - useEffect 依赖 []
- 模拟 componentDidUpdate - useEffect 依赖 [],或者依赖 [a,b]
- 模拟 componentWillUnmount - useEffect 中返回一个函数
useEffect 让纯函数有了副作用
- 默认情况下,执行纯函数,输入参数,返回结果,无副作用
- 所谓副作用,就是对函数之外造成影响,如设置全局定制任务
- 而组件需要副作用,所有需要 useEffect “钩” 到纯函数中
用 useEffect 模拟 WillUnMount 时的注意事项
先看一个好友在线的例子
使用 class 组件实现
import React from "react";
class FriendStatus extends React.Component {
constructor(props) {
super(props);
this.state = {
status: false // 默认当前不在线
}
}
render() {
return <div>
好友 {this.props.friendId} 在线状态: {this.state.status}
</div>
}
componentDidMount() {
console.log(`开始监听 ${this.props.friendId} 的在线状态`)
}
componentWillUnmount() {
console.log(`结束监听 ${this.props.friendId} 的在线状态`)
}
// friendId 更新
componentDidUpdate(prevProps) {
console.log(`结束监听 ${prevProps.friendId} 的在线状态`)
console.log(`开始监听 ${this.props.friendId} 的在线状态`)
}
}
export default FriendStatus
然后调用
import React, {useState} from "react";
import FriendStatus from "./FriendStatusClass";
function App() {
const [flag, setFlag] = useState(true)
const [id, setId] = useState(1)
return <div>
<button onClick={() => setFlag(false)}>设置 flag</button>
<button onClick={() => setId(id + 1)}>设置 ID</button>
{flag && <FriendStatus friendId={id}></FriendStatus>}
</div>
}
export default App
执行结果为
开始监听 1 的在线状态
结束监听 1 的在线状态
开始监听 2 的在线状态
结束监听 2 的在线状态
使用函数组件实现
import React, {useEffect, useState} from "react";
function FriendStatus({friendId}) {
const [status, setStatus] = useState(false)
// DidMount 和 DidUpdate
useEffect(() => {
console.log(`开始监听 ${friendId} 的在线状态`)
// 【特别注意】
// 此处并不完全等同于 willUnMount
// props 发生变化,即更新,也会执行结束监听
// 准确的说:返回函数,会在下一次 effect 执行之前,被执行
return () => {
console.log(`结束监听 ${friendId} 的在线状态`)
}
})
return <div>
好友 {friendId} 在线状态: {status.toString()}
</div>
}
export default FriendStatus
useEffect 中返回函数 fn
- useEffect 依赖 [],组件销毁时执行 fn,等于 WillUnMount
- useEffect 无依赖或依赖 [a,b],组件更新时执行 fn
- 即,下一次执行 useEffect 之前,就会执行 fn,无论更新或卸载