useEffect() 副作用钩子
useEffect
相当于 componentDidMount
(组件挂载),componentDidUpdate
(组件更新) 和 componentWillUnmount
(组件将要销毁) 这三个生命周期函数的组合。
useEffect(() => {
...
},[])
-
useEffect
可以接收两个参数,第一个参数接收一个函数
,可以用来做一些副作用,比如异步请求,修改外部参数等行为;返回值(如果有)则在组件销毁或者调用函数前调用。 - 第二个参数是一个数组,数组中的内容可以称之为
依赖项
,当数组中的值发生变化就会触发执行 useEffect 第一个参数中的函数。
理解函数副作用
对于React组件来说,主作用是根据数据(state
/props
)渲染UI,除此之外都是副作用(比如手动修改DOM、发送ajax请求)。
常见的副作用:
- 数据请求(发送ajax)
- 手动修改 DOM
- localstorage操作
useEffect
函数的作用就是为react
函数组件提供副作用
函数中有返回值
useEffect
第一个参数函数中有return
返回值,即返回值相当于销毁。
相当于原来生命周期的componentWillUnmount
(组件销毁前执行)
使用场景
- 取消订阅
- 清除定时器
- 清除
window.onresize
窗口方法
import React ,{useState,useEffect}from 'react'
function Test() {
useEffect(() => {
let timer = setInterval(() => {
console.log('this is effect');
}, 1000)
// 这里return 一个回调函数,在函数中清除副作用
return () => {
clearInterval(timer);
}
})
return (
<div>Test</div>
)
}
export default function App() {
const [flag, setFlag] = useState(true);
return (
<div>
{flag ? <Test/> : null}
<div>
<button onClick={() => setFlag(!flag)}>点击</button>
</div>
</div>
)
}
点击按钮,Test
组件卸载,清除定时器timer
。
默认状态(无依赖项)
useEffect
不传递第二个参数
,表示不监听任何参数的变化。
每次渲染DOM
之后,都会执行 useEffect
中的第一个函数。
import React from 'react'
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("触发副作用");
});
return (
<div>
<p>点击{count}次</p>
<button onClick={() => setCount(count + 1)}>Click</button>
</div>
)
}
- 组件初始化时触发一次
- 当每次点击按钮时,
count
发生改变,组件更新。控制台每次都会打印log。
依赖项为空数组
useEffect
函数还可以接收第二个参数,作为该副作用的依赖项
,当第二个参数 传入一个空数组[]
时,表明只有 组件初始化的时候执行一次
相当于componentDidMount
(组件挂载)
import React from 'react'
export default function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("触发副作用");
document.title = `点击了${count}次`;
}, []); // 注意这里,传入 []
return (
<div>
<p>点击{count}次</p>
<button onClick={() => setCount(count + 1)}>Click</button>
</div>
)
}
- 组件初始化时触发一次
- 当点击按钮时,
title
不再改变。控制台不再打印log。
依赖特定项
当依赖项数组
中传入值时,那么该副作用会在 组件初始化的时候执行一次,依赖的特定项变化时会再次执行
就像componentDidMount
和componentDidUpdate
组合的生命周期函数一样
function App() {
const [count, setCount] = useState(0);
const [name, setName] = useState('李白');
useEffect(() => {
console.log('触发渲染')
document.title = `clicked ${count} times`;
console.log('name: ', {name});
},[count]) // 这里我们传入 count,不传name
return (
<>
<p>当前次数:{count}</p>
<p><button onClick={() => setCount(count + 1)}>累计</button></p>
<p><button onClick={() => setName("杜甫")}>改名{name}</button></p>
</>
)
}
- 当我们点击 “累计” 按钮时,控制台会打印log,title也会改变,
- 但是我们点击 “改名”时,控制台不会打印log。
- 因为我们在依赖项数组中传入了 count 而没有 name。
发送网络请求
不可以直接在 useEffect 的回调函数外层直接包裹await,因为异步会导致清理函数无法立即返回
❌错误示例:
useEffect(async () => {
const res = await getData('url');
console.log(res);
})
可在 useEffect 中定义一个请求数据方法,调用。
正确示例:
useEffect(() => {
async function initData() {
const res = await getData('url');
console.log(res);
}
initData()
}, []) // 仅组件初始化时调用