# 2-6_單向資料流、一律重繪渲染策略 ## 2-6-1_單向資料流 --- ### 【資料驅動畫面】 - 單向資料流 - `one-way dataflow` - 現代主流框架的設計模式( design pattern) --- ![image](https://hackmd.io/_uploads/r1w5cENRa.png) - 畫面結果 = 原始資料透過模板 + 邏輯所產生的延伸結果 - 單向 - 不可逆 - 只有當資料更新時,畫面才會更新 - 不能在相關的資料更新以外的情況被修改 --- ### 【資料與畫面的分離管理:單一資料來源】 - 將資料管理與畫面渲染進行分開處理,並獨立定義 --- - 不獨立定義原始資料 - 直接操作 DOM,反映使用者的行為 - 難以保證資料的完整與一致 - 資料與畫面分離 - 更新原始資料,反映原始資料的變化 - 提高資料的穩定與可靠 --- - 單一資料來源 - `Single source of truth` - 只有源頭的原始資料才是畫面的來源 - 同個概念的資料不應該在多個地方存在 --- ### 【限縮變因的價值】 - 畫面不會因為資料變化以外的任何原因而隨意改變 - 資料變動 - 開發者的手動觸發資料更新 - 畫面結果 - 原始資料 - 模板邏輯 --- - 價值 - 提高可維護性 - 提升可讀性 - 減少資料意外出錯 - 更好的效能 --- ## 2-6-2_實現單向資料流的 DOM 渲染策略 --- ### 【策略一:當資料更新後,人工判斷並手動修改所有應受到連動更新的 DOM element】 ```javascript! function incrementCounterAndUpdateDOM(index) { counterValues[index] += 1; // 資料更新後,需要具體知道這次資料的更新會影響到的 DOM 範圍,並且手動一一去更新: // 修改某個 counter 的 value 資料後, // 該 counter 對應的 <li> 裡面的 <span> 的文字內容會需要更新 document .querySelectorAll('#counter-list > li > span') .item(index) .textContent = counterValues[index]; // 修改某個 counter value 資料後,也會需要重新計算並更新 counter sum 的文字內容 document .querySelector('#counter-sum > span') .textContent = getNumbersSum(counterValues); } ``` > <https://codesandbox.io/s/96fzf5> --- - 只手動操作資料更新時,會影響到的 DOM element ![image](https://hackmd.io/_uploads/H17F6VEC6.png) --- - 好處: - 只要開發者 DOM 操作得夠簡潔精準,可以減少因為多餘 DOM 操作造成的效能浪費 - 風險: - 仰賴開發者的人為判斷、以及對 DOM 的精確手動操作 --- ### 【策略二:當資料更新後,一律將整個畫面的 DOM element 全部清除,再以最新的原始資料來全部重繪】 ```javascript! // 每次要繪製新的畫面之前,都先把整個瀏覽器畫面全部清空 document.body.innerHTML = ''; ``` ![image](https://hackmd.io/_uploads/H1dmJHN0p.png) > <https://codesandbox.io/s/ke7msp> --- - 好處: - 只要將資料、模板定義好,當資料更新後都會一律重新繪製畫面 - 缺點: - 效能浪費 --- ### 【總結:整理一下以上 2 種渲染策略的優缺點】 | | 優點 | 缺點 | | -------------------------- | -------------------------------------------------- | ------------------------ | | 策略一:手動更新對應的 DOM | 只要開發者的 DOM 操作夠精準,就能減少效能浪費 | 仰賴人為判斷,非常困難 | | 策略二:一律重繪 | 開發者只需要關注模板定義、資料更新的處理,直覺簡單 | 會有多餘不必要的 DOM 操作而影響效能 | --- ### 【前端框架的處理策略】 - 不論何種策略,都有明顯的缺點 - 資料更新後的畫面連動更新 - 大多數的前端框架可以 **同時保留優點並解決缺點** --- - Vue.js - 策略一 - 追蹤資料與模板的綁定關係,監聽資料去更新畫面 - React.js - 策略二 - 一律重繪 --- ## 2-6-3_React 中的一律重繪渲染策略 - 既然一律重繪很浪費效能,那就改成一律重繪虛擬的畫面結構資料,也就是 React element - Virtual DOM 只是普通的自訂變數資料 - 不像 DOM 會與瀏覽器引擎綁定 --- - React render: - 產生 React element 的流程 - React re-render: - 重繪 React element 的流程 - 以新的原始資料重新產生新版的 React element - 「以新的資料(props 或 state)重新再執行一次 component function,並產生新版的 React elements」 --- - React 會以 component 作為一律重繪的切分單位 - 當我們呼叫一個 state 的 setState 方法時,React 就只會重繪該 state 所屬的 component 以及它底下的所有子孫 components,而不會整個 App 都重繪 --- ## Review --- ### 單向資料流是什麼 --- ### 實現單向資料流的策略有哪些?分別的優缺點為何? --- ### React 為了維護單向資料流所採用的策略是什麼?以及是如何解決缺點的? --- ## Reference > 《React 思維進化:一次打破常見的觀念誤解,躍升專業前端開發者》-2024 > <https://www.tenlong.com.tw/products/9786263337695> > > 《[Day 09] 單向資料流 & DOM 渲染策略》-2023 > <https://ithelp.ithome.com.tw/articles/10296750> > > 《[Day 10] React 畫面更新的核心機制(上):一律重繪渲染策略》-2023 > <https://ithelp.ithome.com.tw/articles/10298007> --- ## Q - `one-way data flow` ```markdown! This is called one-way data flow because the data flows down from the top-level component to the ones at the bottom of the tree. ``` > <https://react.dev/learn/thinking-in-react> ---
{"contributors":"[{\"id\":\"24187e66-a778-4778-a2dc-98f9cdf79fe0\",\"add\":3528,\"del\":47}]","description":"","title":"2-6_單向資料流、一律重繪渲染策略","image":"https://hackmd.io/_uploads/HJPUNr4Ap.jpg"}
    364 views