React Hooks的深入理解与使用(7)
这里有一个点需要重视!这种解绑的模式跟componentWillUnmount不一样。componentWillUnmount只会在组件被销毁前执行一次而已,而useEffect里的函数,每次组件渲染后都会执行一遍,包括副作用函数返回的这个清理函数也会重新执行一遍。所以我们一起来看一下下面这个问题。
为什么要让副作用函数每次组件更新都执行一遍?
我们先看以前的模式:
componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); }
很清除,我们在componentDidMount注册,再在componentWillUnmount清除注册。但假如这时候props.friend.id变了怎么办?我们不得不再添加一个componentDidUpdate来处理这种情况:
componentDidUpdate(prevProps) { // 先把上一个friend.id解绑 ChatAPI.unsubscribeFromFriendStatus( prevProps.friend.id, this.handleStatusChange ); // 再重新注册新但friend.id ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); }
看到了吗?很繁琐,而我们但useEffect则没这个问题,因为它在每次组件更新后都会重新执行一遍。所以代码的执行顺序是这样的:
1.页面首次渲染
2.替friend.id=1的朋友注册
3.突然friend.id变成了2
4.页面重新渲染
5.清除friend.id=1的绑定
6.替friend.id=2的朋友注册
怎么跳过一些不必要的副作用函数
按照上一节的思路,每次重新渲染都要执行一遍这些副作用函数,显然是不经济的。怎么跳过一些不必要的计算呢?我们只需要给useEffect传第二个参数即可。用第二个参数来告诉react只有当这个参数的值发生改变时,才执行我们传的副作用函数(第一个参数)。
useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // 只有当count的值发生变化时,才会重新执行`document.title`这一句
当我们第二个参数传一个空数组[]时,其实就相当于只在首次渲染的时候执行。也就是componentDidMount加componentWillUnmount的模式。不过这种用法可能带来bug,少用。
还有哪些自带的Effect Hooks?
除了上文重点介绍的useState和useEffect,react还给我们提供来很多有用的hooks:
- useContext
- useReducer
- useCallback
- useMemo
- useRef
- useImperativeMethods
- useMutationEffect
- useLayoutEffect
我不再一一介绍,大家自行去查阅官方文档。