在元件之間共享狀態
有時,你會希望兩個元件的狀態始終一起變化。要做到這一點,請從兩者中移除狀態,將其移至它們最近的共同父元件,然後透過 props 向下傳遞給它們。這被稱為狀態提升,並且是編寫 React 程式碼時最常做的事情之一。
您將學習
- 如何透過狀態提升在元件之間共享狀態
- 什麼是受控與非受控元件
透過範例提升狀態
在這個範例中,父元件Accordion渲染兩個獨立的Panel:
AccordionPanelPanel
每個Panel元件都有一個布林值isActive狀態,決定其內容是否可見。
按下兩個面板的顯示按鈕:
請注意,按下一個面板的按鈕不會影響另一個面板——它們是獨立的。


最初,每個Panel的isActive狀態是false,所以它們都顯示為摺疊狀態


點擊任一Panel的按鈕只會更新該Panel的isActive狀態
但現在假設你想改變設計,使得在任何時候只有一個面板是展開的。按照這個設計,展開第二個面板應該會摺疊第一個面板。你會怎麼做?
要協調這兩個面板,你需要透過三個步驟將它們的狀態「提升」到父元件:
- 移除子元件中的狀態。
- 從共同父元件傳遞硬編碼的資料。
- 將狀態新增到共同父元件,並與事件處理器一起向下傳遞。
這將允許Accordion元件協調兩個Panel,並且一次只展開一個。
步驟 1:從子元件中移除狀態
你將把Panel的isActive控制權交給其父元件。這意味著父元件將把isActive作為 prop 傳遞給Panel。首先,從Panel元件中移除這一行:
取而代之,將isActive加入到Panel的屬性清單中:
現在,Panel的父元件可以透過控制isActive,方法是將其作為屬性向下傳遞。 相反地,Panel元件現在對於沒有控制權 的值 isActive——這現在取決於父元件!
步驟 2:從共同的父元件傳遞硬編碼資料
要提升狀態,你必須找到你想要協調的 兩個 子元件的最接近的共同父元件:
Accordion(最接近的共同父元件)PanelPanel
在這個例子中,它是Accordion元件。由於它在兩個面板之上並且可以控制它們的屬性,它將成為哪個面板目前處於活動狀態的「單一真實來源」。讓Accordion元件向兩個面板傳遞一個硬編碼的isActive值(例如,true):
嘗試編輯 Accordion元件中的硬編碼isActive 值,並查看螢幕上的結果。
步驟 3:為共同的父元件加入狀態
提升狀態通常會改變你儲存為狀態的內容的性質。
在這個情況下,一次應該只有一個面板處於活動狀態。這意味著Accordion 共同父元件需要追蹤 哪個面板是活動的。它可以使用一個數字作為活動布林值 的索引來作為狀態變數,而不是 Panel:
當 activeIndex 為 0時,第一個面板是活動的;當它為1時,則是第二個。
點擊任一 Panel中的「顯示」按鈕需要改變Accordion中的活動索引。一個Panel無法直接設定activeIndex 狀態,因為它定義在 Accordion內部。Accordion 元件需要 明確允許 Panel元件改變其狀態,方法是將事件處理函式作為屬性向下傳遞:
現在,<button> 內部的 Panel 將使用 onShow屬性作為其點擊事件處理函式:
這樣就完成了狀態提升!將狀態移入共同的父元件讓你能夠協調兩個面板。使用活動索引而非兩個「是否顯示」標誌,確保了在給定時間只有一個面板處於活動狀態。而將事件處理函式向下傳遞給子元件,則允許子元件改變父元件的狀態。


最初,Accordion的activeIndex 是 0,所以第一個Panel 收到 isActive = true


當 Accordion的activeIndex 狀態變更為 1時,第二個Panel則會收到isActive = true。
每個狀態的單一真實來源
在 React 應用程式中,許多元件都會有自己的狀態。有些狀態可能「存在」於接近葉子元件(樹狀結構底部的元件)的地方,例如輸入框。其他狀態可能「存在」於應用程式的頂層附近。例如,即使是客戶端路由函式庫,通常也是透過將當前路由儲存在 React 狀態中,並透過 props 向下傳遞來實現的!
對於每個獨特的狀態片段,你將選擇「擁有」它的元件。 這個原則也被稱為擁有 「單一真實來源」。這並不意味著所有狀態都存在於一個地方——而是對於每個狀態片段,都有一個特定的 元件來保存該資訊。與其在元件之間複製共享狀態,不如將其 提升到它們共同的父元件,並向下傳遞給需要它的子元件。
你的應用程式會隨著你的工作而改變。在弄清楚每個狀態片段「存在」於何處的過程中,將狀態向下移動或向上移動是很常見的。這都是過程的一部分!
要透過更多元件來體驗這種感覺,請閱讀 React 思維。
總結
- 當你想要協調兩個元件時,將它們的狀態移到它們的共同父元件。
- 然後透過 props 從它們的共同父元件向下傳遞資訊。
- 最後,將事件處理函式向下傳遞,以便子元件可以改變父元件的狀態。
- 將元件視為「受控」(由 props 驅動)或「非受控」(由狀態驅動)是很有用的。
