React要更新,就像渣男会变心

你们好,我是卡颂。html

今天和同事聊天,我说他是个铁憨憨,不会和女生聊天。react

他啪的一下跳起来,“我可懂情调了”数组

“哦?那你来句土味情话。”markdown

他清清嗓子,压低了腔调,望向远方,缓缓道:ide

若是我是component,我对你的情愫在didMount时燃起,直到我生命unmount时熄灭函数

正当他沉浸在YY的世界没法自拔时,我说:oop

你知道在React18componentDidMountcomponentWillUnmount可能调用屡次么?学习

呵,渣男!ui

从Strict Mode谈起

React有个特性 —— Strict Mode,被StrictMode包裹的组件在DEV环境会对不推荐写法有更严格的提示与辅助检测行为。spa

<StrictMode>
  <div> <ComponentOne /> <ComponentTwo /> </div>
</StrictMode>
复制代码

辅助检测行为是指部分方法会被React重复调用,帮助开发者更容易发现不规范使用这些方法时的潜在bug

全部会被重复调用的API见StrictMode文档

举个例子:

function App() {
  const [num, update] = useState(0);

  function onClick() {
    update(num + 1);
  }

  console.log('render');

  return (
    <p onClick={onClick}>{num}</p>
  );
}
复制代码

AppStrictMode包裹,点击p触发更新后,App组件会render两次。

v17以前,例子中console.log会执行两次。但在v17以后,React覆写了console方法,因此console.log只会执行一次,但组件实际会render两次

这么作的目的是:做为函数组件,App反作用应该在useEffect回调中执行。

若是不规范书写反作用(好比在组件函数体内写反作用),那么重复render更容易暴露可能产生的bug

铺垫完背景。接下来,让咱们揭露React善变的渣男行径。

最近刷v18讨论组时忽然发现:StrictMode中会增长一条Strict Effect规则。

Strict Effect

简单的说,相似上文讲到的部分APIStrictMode下会重复执行。

Strict Effect规则会让useEffectuseLayoutEffectStrictMode下也会重复执行。

好比:

function App() {
  // 或useLayoutEffect
  useEffect(() => {
    // 逻辑1
    return () => // 逻辑2;
  }, [])
  
  // ...
}
复制代码

在当前React中,组件mount时,执行逻辑1。

而在Strict Effect规则下,mount时的逻辑以下:

  • 组件mount时,执行逻辑1

  • React模拟组件unmount,执行逻辑2

  • React模拟组件mount,执行逻辑1

注意,这里useEffect的依赖项是[],在以往的认知里,依赖项为空数组意味着该useEffect逻辑只会在mount时执行一次。

而在v18Strict Mode,因为包含了Strict Effect规则,mount时的useEffect逻辑会被重复执行。

某种程度上讲,这种打破开发者既有认知的Breaking Change,比Concurrent Mode更让人难以接受。

那么React团队为何要设计这条规则呢?

一切为了Offscreen

Offscreen是一个开发中的API,预计会在某个v18的小版本发布。

他的功能相似Vue中的keep-alive,用来在组件失活时在后台保存组件状态。

举个Tab切换的例子,在PostsArchive之间切换Tab

当切换到Posts时,Archive属于失活状态。

若是不须要保存状态,则销毁Archive组件。当切换到Archive Tab时,再从新mount Archive

当须要保存状态时,只能将PostsArchive的状态保存在他们的父组件或状态管理(好比Redux)中。

而有了Offscreen API,在Fiber树(能够理解为虚拟DOM树)层面,能够保存失活的组件结构与状态。

这个API的应用场景主要包括:

  • 切换路由时保存以前路由的状态

  • 预加载将要切换的路由

如今问题来了:当Offscreen组件从失活变为活动,会触发什么生命周期函数呢?

答案是:componentDidMount以及:

useEffect(() => {
   // 触发这个逻辑...
}, [])
复制代码

Offscreen组件从活动变为失活时,会触发componentWillUnmount与:

useEffect(() => {
   // ...
   return () => {
     // 触发这个逻辑...
   }
}, [])
复制代码

因此,这些曾经被认为在组件生命周期中只会触发一次的方法,因为Offscreen,在将来可能会屡次触发。

这也是React提早在StrictMode中加上Strict Effect规则的缘由。

就像渣男变心前都会有些反常的举动。

React18是真的挑战

无论是Offscreen仍是Concurrent Mode,能够预见随着v18的到来,React会更强大,相应的学习曲线会更陡峭。

这既是机遇,也是挑战。

千万别等变化一股脑到眼前时再埋怨:

你个渣男,当初说好一心一意只会触发一次,如今为了妖艳新特性,背叛咱们的诺言。

到那时React只会拍拍屁股转身,留下不羁的背影:

相关文章
相关标签/搜索