# React 思維進化 ## 5-4~5-5 --- ## 觀念回顧 - 對 useEffect 的 dependencies 保持誠實,將依賴資料填入dependencies 陣列中 - useEffect 是用於資料同步化到副作用處理的處理,預設是每次 render 都會自動觸發,而 dependencies 是跳過不必要副作用處理的**效能優化**,i.e. 即使將 dependencies 拿掉,程式碼也會被正確執行 - 如果需要控制執行時機,就透過開發者撰寫**條件式**來符合商業邏輯 --- e.g. 使用 useRef flag 判斷此商業邏輯只有執行一次 ![image](https://hackmd.io/_uploads/Hy0Bjp4IA.png =70%x) --- ## [React 18 嚴格模式](https://codesandbox.io/p/sandbox/qr-code-5-3-6-forked-6r86h2?file=%2Fsrc%2FApp.jsx%3A10%2C10) - 目的:幫助開發者檢查副作用處理是否安全可靠 - 在範例中,Effect function 在 React 18 中在 mount 時被執行兩次 --- - 在 React 的未來版本的規劃中,符合:component 需要被設計得足夠彈性,即使多次 mount 與 unmount 也不會壞掉 - 常用功能 Hot Refresh、未來功能 Offscreen API - Resuable State 概念 --- ### 常用功能 Hot Refresh React 開發存檔時,會 unmount component,再立刻以新版 component mount 它。過程中 component state 是會被保留不會被清除 ### 未來功能 Offscreen API 畫面切換時會保留 component state 與其對應實際 DOM element,直到 component 需要再次顯示時,便可以以之前的 state 狀態再次 mount,以提升效能 --- ### Resuable state 概念 - 在 React 未來版本中,當畫面中移除 component 後,仍會可以保留 component state 狀態,以便在需要時可以快速還原並再次 mount - 生命週期不止 mount 與 unmount 一次 - 即使依賴資料沒有更新,effect function 也可能再次被執行 --- ### 目標:「無論重複執行都不多少次都不會壞掉」 - 在嚴格模式中, component 模擬 「mount ⇒ unmount ⇒ mount 行為」。幫助開發者來確保副作用設計的彈性,為 React 未來規劃做好準備 - 因此 component mount 時會有「執行 effect function ⇒ cleanup function ⇒ effect function」的動作 --- 透過 React 18 的嚴格模式介紹,讓我們了解 React 的未來規劃中,透過滿足 reusable state 概念達到「副作用處理無論重複執行多少次都不會壞掉」的目標 --- ## 觀念檢測 - 為什麼在 React 18 的嚴格模式且為開發環境的版本中,component 的 effect 函式會在 mount 時自動被執行兩次? - Reusable state 是什麼? - 為了滿足 reusable state 對於程式碼彈性的要求,我們應該讓副作用處理的設計滿足什麼目標? --- ## 觀念回顧 - 副作用處理理想的效果是造成的影響是可逆的,無論重複執行多少次都不會壞掉 --- ## 副作用處理常見的情境設計技巧 ### 常見副作用設計問題 1. 疊加性質而非覆蓋性質操作 隨著執行次數變多而不斷疊加時,如果沒有設計 cleanup function 來做取消或逆轉處理,就可能再多次重複執行後造成非預期結果。 --- ### 常見副作用設計問題 2. Race condition 多個操作的相對時間順序影響程式存取資源的行為,可能造成不預期結果。e.g. 兩個人同時在同一個網站上修改同一項資料、Fetch Server 端 API 資料回傳順序 --- ### 常見副作用設計問題 3. Memory leak 某段程式碼不用了,但記憶體空間尚未被釋放,導致部分記憶體無法被使用。此時除非將整個執行中的應用程式關閉並重新執行,否則記憶體將會被持續佔用。 --- 當副作用會啟動持續性的監聽工作,但沒有做對應的取消訂閱就有可能在 component unmount 之後持續監聽,造成效能浪費。e.g. 根據 `props.id` 來訂閱特定訂單的狀態變化監聽(5-1, p. 279-281) ![image](https://hackmd.io/_uploads/r1ZD3QrUC.png =70%x) --- 一般來說,以上問題都可透過 cleanup function 做適時的處理 --- ### 情境 1:Fetch Server 端 API ![image](https://hackmd.io/_uploads/BkBp-zSI0.png =70%x) --- ![image](https://hackmd.io/_uploads/SJ73LGB8A.png =80%x) 因為前面 fetch 回傳較晚,因此 state 留下的是舊的 data1 --- 加上 Flag 判定是否要跳過該次回傳結果 ![image](https://hackmd.io/_uploads/B17ArGBL0.png =70%x) --- ![image](https://hackmd.io/_uploads/BJybymrIR.png =80%x) --- 實務上最推薦使用第三方套件解決 race condition 問題,並內建快取、效能調校等功能。e.g. React Query, SWR, React apollo --- ### 情境 2:控制外部套件 - 新增判斷去確保第三方套件初始化不會被重複執行 - 因為沒有依賴資料,所以可以填空陣列 ![image](https://hackmd.io/_uploads/S1s6R7H80.png =70%x) --- 將 React component 內的資料向外部套件進行同步化。每當 state 與前一次不相同時,就會執行同步到 mapmanager ![image](https://hackmd.io/_uploads/rJwkg4rU0.png =70%x) 若 zoomLevel 更新頻繁,也可以加入 throttle 優化效能與穩定性,以確保一定時間間隔內只需要執行一次同步到 mapmanager --- ### 情境 3:監聽與訂閱事件 訂閱 DOM 事件、自定義事件,並且需要做取消訂閱,否則該訂閱會在 component unmount 後持續運作,造成 memory leak ![image](https://hackmd.io/_uploads/r1ldrVB8A.png =60%x) --- ### 情境 4:使用者觸發事件不該是副作用處理 不應該把「使用者操作行為」處理放在 effect function 中,因為他會隨著 render 被重複執行,即使 cleanup 與無法清除 server 端的 side effect ![image](https://hackmd.io/_uploads/HJ8guEBL0.pngg =70%x) --- ## 觀念檢測 - 我們如何解決副作用設計中「疊加性質而非覆蓋性質的操作」的問題? - 我們如何解決副作用設計中「rece condition」的問題? - 我們如何解決副作用設計中「memory leak」的問題? --- Thank you !
{"title":"React 思維進化","description":"Try   HackMD用 HackMD 做簡報HackMD 整合了 reveal.js,讓我們可以用 Markdown 輕鬆寫簡報。讓我們開始吧!","contributors":"[{\"id\":\"f70cb22d-4d8b-4e29-a690-f808410dd689\",\"add\":5053,\"del\":1554}]"}
    35 views