useEffect简介
useEffect
,字面意思可以理解为"执行副作用操作",对比于以前react class
的写法,可以把 useEffect
看做 componentDidMount
,componentDidUpdate
和 componentWillUnmount
这三个函数的组合。
为了便于理解useEffect到底是个什么东西,我们来对比下class
的写法和useEffect
的写法
class
组件写法
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
console.log(`You clicked ${count} times`);
}
componentDidUpdate() {
console.log(`You clicked ${count} times`);
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
useEffect
组件写法
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// 相当于 componentDidMount 和 componentDidUpdate
useEffect(() => {
console.log(`You clicked ${count} times`);
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
注意点
-
useEffect
会在每次渲染后都执行,也就是说在第一次渲染之后和每次更新之后都会执行。 -
useEffect
执行的effect是异步的,不会阻塞浏览器更新屏幕,但是在某些场景下这种异步的方式可能并不合适,比如初始布局场景,这个时候可能需要用到useLayoutEffect
(与useEffect
相同,但它会在所有的 DOM 变更之后同步调用 effect)。
清除effect
在React class
中,我们通常会在componentDidMount
中设置订阅,并在componentWillUnmount
中清除它,那么在useEffect
中设置的订阅,我们如何清除呢?
我们可以在useEffect
的回调函数中返回一个函数,React 将会在执行清除操作时调用它。
useEffect(() => {
function handleScroll() {console.log('scroll')}
window.addEventListener('scroll', handleScroll)
// 相当于componentWillUnmount
return function cleanup() {
window.removeEventListener('scroll', handleScroll)
};
});
effect
参数
在上面我们介绍到可以通过返回一个函数来实现componentWillUnmount
的功能,从而实现解绑事件等功能,但是细心的同学可能会发现上面的例子有个问题,就是每次重新渲染的时候,这个useEffect
回调就会触发,从而不断的进行绑定,解绑,这显然不是我们想要的,那么如何实现像componentDidMount
和componentWillUnmount
那样只执行一次呢?这里就需要用到useEffect
的第二个参数了。
- 如果什么都不传,那么每次渲染都会执行。
- 如果传一个空数组,那么就只会运行一次
effect
,并且effect
内部的props
和state
会一直拥有其初始值。 - 如果传的是一个包含属性值的数组,那么只有当数组里的值发生变化的时候才会触发
useEffect
回调。
每次都触发
// 相当于 componentDidMount 和 componentDidUpdate
useEffect(() => {
console.log(`You clicked ${count} times`);
});
只需要触发一次
// 由于第二个参数传的是空数组,所以这里相当于componentDidMount
useEffect(() => {
function handleScroll() {}
window.addEventListener('scroll', handleScroll)
// 相当于componentWillUnmount
return function cleanup() {
window.removeEventListener('scroll', handleScroll)
};
}, []);
当属性值变化时才触发
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
const [show, setShow] = useState(false);
// 只有当count发生变化的时候才会触发,show发生变化不会触发
useEffect(() => {
console.log(`You clicked ${count} times`);
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<button onClick={() => setShow(!show)}>
Toggle show
</button>
</div>
);
}
网友评论