在前面的描述中或多或少涉及到对于effect的清理,只是为了便于一个理解,但描述并不完全准确。
例如下面的例子:
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange);
};
});
假设第一次渲染的时候props是{id: 10},第二次渲染的时候是{id: 20}。你可能会认为发生了下面的这些事:
React 清除了 {id: 10}的effect。
React 渲染{id: 20}的UI。
React 运行{id: 20}的effect。
但是实际情况并非如此,如果按照这种心智模型来理解,那么在清除时候,获取的值是之前的旧值,因为清除是在渲染新UI之前完成的。这和之前说到的React只会在浏览器绘制之后执行effects矛盾。
React这样做的好处是不会阻塞浏览器的一个渲染(屏幕更新)。当然,按照这个规则,effect的清除也被延迟到了浏览器绘制UI之后。那么正确的执行顺序应该是:
React渲染了id 20 的UI
React清除了id 10的effect
React运行id 20的effect
那么为啥effect里清除的是旧的呐?
组件内的每一个函数(包括事件处理函数,effects,定时器或者API调用等等)会捕获定义它们的那次渲染中的props和state。
那么,effect的清除并不会读取到“最新”的props,它只能读取到定义它那次渲染中props的值
人类发展的进程中淘汰的永远都是不思进取的守旧派。React中亦是如此思想,或许激进,但大多数人们总期待“新桃换旧符”。