渲染與提交
在您的元件顯示於螢幕之前,它們必須先由 React 進行渲染。了解此過程中的步驟將有助於您思考程式碼的執行方式並解釋其行為。
您將學習
- 在 React 中渲染的含義
- React 何時以及為何渲染元件
- 在螢幕上顯示元件所涉及的步驟
- 為何渲染不一定會產生 DOM 更新
想像您的元件是廚房裡的廚師,用食材組裝美味的菜餚。在這個情境中,React 是服務生,負責接收顧客的點單並將餐點送上。這個請求與提供使用者介面的過程包含三個步驟:
- 觸發渲染(將客人的訂單送到廚房)
- 渲染元件(在廚房準備訂單)
- 提交到 DOM(將訂單放到桌上)
觸發
渲染
提交
步驟 1:觸發渲染
元件渲染有兩個原因:
- 這是元件的初始渲染。
- 元件(或其某個祖先元件)的狀態已更新。
初始渲染
當您的應用程式啟動時,您需要觸發初始渲染。框架和沙箱有時會隱藏此程式碼,但它是透過呼叫createRoot並傳入目標 DOM 節點,然後使用您的元件呼叫其render方法來完成的:
試著將root.render()呼叫註解掉,看看元件是否消失!
狀態更新時重新渲染
元件完成初始渲染後,您可以透過使用set 函式更新其狀態來觸發後續的渲染。更新元件的狀態會自動將渲染排入佇列。(您可以想像這就像餐廳客人在點完第一道菜後,根據他們口渴或飢餓的狀態,又點了茶、甜點和各種東西。)
狀態更新...
...觸發...
...渲染!
步驟 2:React 渲染您的元件
在您觸發渲染後,React 會呼叫您的元件以計算要在螢幕上顯示什麼。「渲染」就是 React 呼叫您的元件。
- 在初始渲染時,React 會呼叫根元件。
- 對於後續的渲染,React 會呼叫其狀態更新觸發了渲染的函式元件。
這個過程是遞迴的:如果更新的元件返回了其他元件,React 接下來會渲染那個元件,如果該元件也返回了某些內容,它會接著渲染那個元件,依此類推。這個過程將持續進行,直到沒有更多巢狀元件,並且 React 確切知道螢幕上應該顯示什麼為止。
在以下範例中,React 會多次呼叫Gallery()和Image():
- 在初始渲染期間,React 會建立 DOM 節點,用於
<section>、<h1>以及三個<img>標籤。 - 在重新渲染期間,React 會計算自上次渲染以來,它們的哪些屬性(如果有的話)發生了變化。它不會對這些資訊採取任何行動,直到下一個步驟,即提交階段。
陷阱
渲染必須始終是一個純粹的計算:
- 相同的輸入,相同的輸出。給定相同的輸入,一個元件應該總是返回相同的 JSX。(當有人點了番茄沙拉,他們不應該收到洋蔥沙拉!)
- 它只管自己的事。它不應該改變任何在渲染之前就已存在的物件或變數。(一個訂單不應該改變其他人的訂單。)
否則,隨著你的程式碼庫變得越來越複雜,你可能會遇到令人困惑的錯誤和不可預測的行為。在「嚴格模式」下開發時,React 會呼叫每個元件的函式兩次,這有助於發現由不純函式引起的錯誤。
步驟 3:React 將變更提交到 DOM
在渲染(呼叫)你的元件之後,React 將修改 DOM。
- 對於初始渲染,React 將使用appendChild()DOM API 將它建立的所有 DOM 節點放到畫面上。
- 對於重新渲染,React 將應用最小必要的操作(在渲染時計算!)使 DOM 與最新的渲染輸出相匹配。
React 只有在渲染之間存在差異時才會更改 DOM 節點。例如,這裡有一個元件每秒會從其父元件接收不同的 props 並重新渲染。請注意,你可以向<input>中新增一些文字,更新其value,但當元件重新渲染時,文字並不會消失:
這是因為在最後一步中,React 只更新了<h1>的內容為新的time。它看到<input>在 JSX 中出現的位置與上次相同,因此 React 不會觸碰<input>——或其value!
尾聲:瀏覽器繪製
渲染完成且 React 更新了 DOM 之後,瀏覽器將重新繪製畫面。雖然這個過程被稱為「瀏覽器渲染」,但為了避免在整個文件中造成混淆,我們將其稱為「繪製」。

回顧
- React 應用中的任何畫面更新都分為三個步驟:
- 觸發
- 渲染
- 提交
- 你可以使用嚴格模式來找出元件中的錯誤
- 如果渲染結果與上次相同,React 不會觸碰 DOM
