useEffect
1. 说明
- Effect Hook 可以让你在函数组件中执行副作用操作
- 副作用 : 数据获取、设置/销毁定时器以及手动更改 React 组件中的 DOM 都属于副作用
- 在函数组件中,每当DOM完成一次渲染,都会有对应的副作用执行
- 官网提示 :
如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
- 个人建议 :
- 我们要抛开生命周期的固有思维, 还要注意: 生命周期和useEffect是完全不同的。
- 思想
在function组件中,每当DOM完成一次渲染,都会有对应的副作用执行,useEffect用于提供自定义的执行内容,它的第一个参数(作为函数传入)就是自定义的执行内容。为了避免反复执行,传入第二个参数(由监听值组成的数组)作为比较(浅比较)变化的依赖,比较之后值都保持不变时,副作用逻辑就不再执行。
2. 语法
2.1 语法格式
useEffect(callback, deps)
- callback : 回调
- deps : 依赖数组
2.2 语法说明
-
回调执行
- DOM渲染完, 执行一次 useEffect 的回调
- 每次更新之后也会执行 useEffect 的回调
- 每次我们重新渲染,都会生成新的 effect,替换掉之前的
- 总结 : 某种意义上讲,effect 更像是渲染结果的一部分 —— 每个 effect “属于”一次特定的渲染
-
依赖数组
- 可以通过 deps 依赖项 来控制 回调执行的次数
3. 使用
3.1 基本使用
- 验证 : 回调执行
useEffect(() => {
console.log('useEffect')
})
// 更新
<div>函数组件-{count} - {num}</div>
<button onClick={() => setCount(count + 1)}>count+1</button>
- React 会在每次渲染后都运行 Effect
3.1 修改标题案例
// 累加
useEffect(() => {
console.log('useEffect')
document.title = `您点击了 ${count} 次`
})
3.2 根据依赖项执行 useEffect
- 需求 : 只根据count 的变化执行 useEffect
// 初始值
const [count, setCount] = useState(0)
const [num, setNum] = useState(0)
// 点击
<div>函数组件-{count} - {num}</div>
<button onClick={() => setCount(count + 1)}>count+1</button>
<button onClick={() => setNum(num + 1)}>num+1</button>
// useEffect
useEffect(() => {
console.log('useEffect')
// 假如说 只让count 变化的时候才打印 ,num变化的不打印
}, [count])
// }, [count, num]) 依赖项 count 和 num
依赖数组就是用来控制是否应该触发 Effect,从而能够减少不必要的计算,从而优化了性能。具体而言,只要依赖数组中的每一项与上一次渲染相比都没有改变,那么就跳过本次 Effect 的执行
3.3 定时器
- 依赖项 改为 空数组, 永远只会执行一次
- 空数组,不会有变化内容
// 点击
<button onClick={() => setNum(num + 1)}>num+1</button>
useEffect(() => {
setInterval(() => {
console.log('定时器')
}, 1000)
})
// 原因 : 每次点击 新的 useEffect, 创建一个新的定时器
useEffect(() => {
setInterval(() => {
console.log('定时器')
}, 1000)
},[])
// 需要 添加一个空数组 只执行一次
3.3 发送请求
// 点击
<button onClick={() => setNum(num + 1)}>num+1</button>
// 请求
useEffect(() => {
axios
.get('https:/api/public/v1/home/swiperdata')
.then(res => {
console.log('请求结果', res)
})
}, [])
3.5 清除定时器
- 定时器
useEffect(() => {
setInterval(() => {
console.log('定时器')
}, 1000)
})
// 原因 : 每次点击 新的 useEffect, 创建一个新的定时器
- 只创建一次
useEffect(() => {
setInterval(() => {
console.log('定时器')
}, 1000)
},[])
// 依赖空数组 只创建一个定时器
- 打印卸载
useEffect(() => {
setInterval(() => {
console.log('定时器')
}, 1000)
return () => {
console.log('卸载')
}
}, [])
// 演示卸载 :
const Parent = () => {
const [isShow, setShow] = useState(true)
return (<div>
<div onClick={() => setShow(false)}>父</div>
{isShow && <Child></Child>}
</div>)}
- 清除定时器
// let timer 如果把 timer 放到全局的 这里会有警告 后面再解释
useEffect(() => {
const timer = setInterval(() => {
console.log('定时器')
}, 1000)
return () => {
console.log('卸载')
clearInterval(timer)
}
}, [])
3.5 总结
useEffect(callback, []) ==> 类似 : componentDidMount()
useEffect(callback, [count]) ==> 类似 : componentDidUpdate()
useEffect(()=>{
return ()=> {
// 卸载函数
}
}, [count]) ==> 类似 : componentWillUnmount()