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只會拍拍屁股轉身,留下不羈的背影:

相關文章
相關標籤/搜索