携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情
前言
大家好呀,我是L同学。在上篇文章react笔记(十)—— useEffect副作用介绍中,我们学习了useState使用规则、useEffect副作用介绍、useEffect基本使用、useEffect依赖等相关知识点。在本篇文章中,我们将学习到useEffect依赖是一个空数组、useEffect不要对依赖项撒谎、useEffect清理副作用、useState-回调函数参数等相关知识点。
useEffect-依赖是一个空数组
useEffect 的第二个参数,还可以是一个空数组([]) ,表示只在组件第一次渲染后执行 effect。使用场景是 1. 事件绑定 2. 发送请求获取数据 等。
该effect只会在组件第一次渲染后执行,因此,可以执行像事件绑定等只需要执行一次的操作。此时,相当于 class 组件的 componentDidMount 钩子函数的作用。跟 useState Hook 一样,一个组件中也可以调用 useEffect Hook 多次。 推荐一个 useEffect 只处理一个功能,有多个功能时,使用多次 useEffect。
useEffect(() => {
const handleResize = () => {}
window.addEventListener('resize', handleResize)
}, [])
useEffect-不要对依赖项撒谎
useEffect 回调函数中用到的数据(比如,count)就是依赖数据,就应该出现在依赖项数组中。如果 useEffect 回调函数中用到了某个数据,但是,没有出现在依赖项数组中,就会导致一些 Bug 出现。所以,不要对 useEffect 的依赖撒谎。
const App = () => {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = '点击了' + count + '次'
}, [])
return (
<div>
<h1>计数器:{count}</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
<hr />
</div>
)
}
我们来总结一下useEffect的三种使用语法。
// 触发时机:1 第一次渲染会执行 2 每次组件重新渲染都会再次执行
// componentDidMount + ComponentDidUpdate
useEffect(() => {})
// componentDidMount
// 触发时机:只在组件第一次渲染时执行
useEffect(() => {}, [])
// componentDidMount + componentDidUpdate(判断)
// 触发时机:1 第一次渲染会执行 2 当 count 变化时会再次执行
useEffect(() => {}, [count])
useEffect清理副作用
useEffect的返回值是可选的,可省略。也可以返回一个清理函数,用来执行事件解绑等清理操作。清理函数会在组件卸载时以及下一次副作用回调函数调用的时候执行,用于清除上一次的副作用。如果依赖项为空数组,那么会在组件卸载时会执行。相当于组件的componetWillUnmount。一个 useEffect 只处理一个功能,有多个功能时,使用多次 useEffect。
useEffect(() => {
const handleResize = () => {}
window.addEventListener('resize', handleResize)
// 这个返回的函数,会在该组件卸载时来执行
// 因此,可以去执行一些清理操作,比如,解绑 window 的事件、清理定时器 等
return () => window.removeEventListener('resize', handleResize)
})
useState-回调函数参数
useState 的参数可以有两种形式:
- useState(普通的数据) => useState(0) / useState('abc')
- useState(回调函数) => useState(() => { return 初始值 })
- 回调函数的返回值就是状态的初始值
- 该回调函数只会触发一次
// 使用 回调函数 来为 useState 初始化默认值
// 回调函数的返回值就是状态的初始值!
// 注意:该回调函数只会触发一次
const [list, setList] = useState(() => {
return JSON.parse(localStorage.getItem('comments')) || comments
})
如果状态就是一个普通的数据(比如,字符串、数字、数组等)都可以直接使用 useState(普通的数据)。如果状态是经过一些计算得到的,此时,推荐使用 useState(回调函数)。
// 第一种:
const [list, setList] = useState(
JSON.parse(localStorage.getItem('list')) || arr
)
// 可以转化为:
// 这种情况下,只要组件更新,此处的 localStorage 等操作就会重复执行
// const initList = JSON.parse(localStorage.getItem('list')) || comments
// const [list, setList] = useState(initList)
// 第二种:
// 这种方式,因为回调函数只会执行一次,所以,此处的 localStorage 等操作代码只会执行一次
const [list, setList] = useState(() => {
return JSON.parse(localStorage.getItem('comments')) || comments
})
// 在这种情况下,推荐使用第二种方式