React 在組件間共享狀態

在組件間共享狀態

有時候,你希望兩個組件的狀態始終同步更改。要實現這一點,可以將相關 state 從這兩個組件上移除,并把 state 放到它們的公共父級,再通過 props 將 state 傳遞給這兩個組件。這被稱為“狀態提升”,這是編寫 React 代碼時常做的事。

學習內容

  • 如何使用狀態提升在組件之間共享狀態
  • 什么是受控組件和非受控組件

舉例說明一下狀態提升
在這個例子中,父組件 Accordion 渲染了 2 個獨立的 Panel 組件。

  • Accordion
    • Panel
    • Panel

每個 Panel 組件都有一個布爾值 isActive,用于控制其內容是否可見。

import React, { useState } from 'react';
import {Button} from 'antd';// Accordion 父組件
const Accordion:React.FC=()=> {return (<><h2>我的旅游清單</h2><Panel title="未完成打卡地點"><ul><li>北京故宮</li><li>北京天安門</li><li>北京頤和園</li><li>北京王府井</li></ul></Panel><Panel title="已完成打卡地點"><ul><li>上海迪士尼</li><li>深圳世界之窗</li><li>廣州"小蠻腰"</li><li>廣州長隆</li></ul></Panel></>);
}
export default Accordion// 定義 Panel 組件的 props 類型
interface PanelProps {title: string;children: React.ReactNode;
}
// Panel 子組件
const Panel: React.FC<PanelProps>=({title,children})=> {const [isActive, setIsActive] = useState(false);return (<section style={{padding:"10px",background:"#e4e4e4",marginBottom:"10px"}}><h3>{title}</h3>{isActive ? (<p>{children}</p>) : (<Button variant="solid" color="primary" onClick={() => setIsActive(true)}>顯示</Button>)}</section>);
}

在這里插入圖片描述

請點擊 2 個面板中的顯示按鈕:

在這里插入圖片描述
我們發現點擊其中一個面板中的按鈕并不會影響另外一個,他們是獨立的。
在這里插入圖片描述
假設現在你想改變這種行為,以便在任何時候只展開一個面板。在這種設計下,展開第 2 個面板應會折疊第 1 個面板。你該如何做到這一點呢?“

要協調好這兩個面板,我們需要分 3 步將狀態“提升”到他們的父組件中。

  1. 從子組件中 移除 state 。
  2. 從父組件 傳遞 硬編碼數據。
  3. 為共同的父組件添加 state ,并將其與事件處理函數一起向下傳遞。

這樣,Accordion 組件就可以控制 2 個 Panel 組件,保證同一時間只能展開一個。

第 1 步: 從子組件中移除狀態

你將把 Panel 組件對 isActive 的控制權交給他們的父組件。這意味著,父組件會將 isActive 作為 prop 傳給子組件 Panel。我們先從 Panel 組件中 刪除下面這一行:

const [isActive, setIsActive] = useState(false);

然后,把 isActive 加入 Panel 組件的 props 中:

const Panel: React.FC<PanelProps> = ({ title, children, isActive}) => { 

現在 Panel 的父組件就可以通過 向下傳遞 prop 來 控制 isActive。但相反地,Panel 組件對 isActive 的值 沒有控制權 —— 現在完全由父組件決定!

第 2 步: 從公共父組件傳遞硬編碼數據

為了實現狀態提升,必須定位到你想協調的 兩個 子組件最近的公共父組件:

Accordion (最近的公共父組件)
Panel
Panel
在這個例子中,公共父組件是 Accordion。因為它位于兩個面板之上,可以控制它們的 props,所以它將成為當前激活面板的“控制之源”。通過 Accordion 組件將硬編碼值 isActive(例如 true )傳遞給兩個面板:

import React from 'react';
import {Button} from 'antd';// Accordion 父組件
const Accordion:React.FC=()=> {return (<><h2>我的旅游清單</h2><Panel title="未完成打卡地點" isActive={true}><ul><li>北京故宮</li><li>北京天安門</li><li>北京頤和園</li><li>北京王府井</li></ul></Panel><Panel title="已完成打卡地點" isActive={false}><ul><li>上海迪士尼</li><li>深圳世界之窗</li><li>廣州"小蠻腰"</li><li>廣州長隆</li></ul></Panel></>);
}
export default Accordion// 定義 Panel 組件的 props 類型
interface PanelProps {title: string;children: React.ReactNode;isActive:boolean
}
// Panel 子組件
const Panel: React.FC<PanelProps>=({title,children,isActive})=> {return (<section style={{padding:"10px",background:"#e4e4e4",marginBottom:"10px"}}><h3>{title}</h3>{isActive ? (<p>{children}</p>) : (<Button variant="solid" color="primary">顯示</Button>)}</section>);
}

在這里插入圖片描述
你可以嘗試修改 Accordion 組件中 isActive 的值,并在屏幕上查看結果。

第 3 步: 為公共父組件添加狀態

狀態提升通常會改變原狀態的數據存儲類型。

在這個例子中,一次只能激活一個面板。這意味著 Accordion 這個父組件需要記錄 哪個 面板是被激活的面板。我們可以用數字作為當前被激活 Panel 的索引,而不是 boolean 值:

const [activeIndex, setActiveIndex] = useState(0);

當 activeIndex 為 0 時,激活第一個面板,為 1 時,激活第二個面板。

在任意一個 Panel 中點擊“顯示”按鈕都需要更改 Accordion 中的激活索引值。 Panel 中無法直接設置狀態 activeIndex 的值,因為該狀態是在 Accordion 組件內部定義的。 Accordion 組件需要 顯式允許 Panel 組件通過 將事件處理程序作為 prop 向下傳遞 來更改其狀態:

<><PanelisActive={activeIndex === 0}onShow={() => setActiveIndex(0)}>...</Panel><PanelisActive={activeIndex === 1}onShow={() => setActiveIndex(1)}>...</Panel>
</>

現在 Panel 組件中的 將使用 onShow 這個屬性作為其點擊事件的處理程序:

import React, { useState } from 'react';
import {Button} from 'antd';// Accordion 父組件
const Accordion: React.FC = () => {const [activeIndex, setActiveIndex] = useState(0);return (<div><h2 className="text-2xl font-bold mb-4">我的旅游清單</h2><Paneltitle="未完成打卡地點"isActive={activeIndex === 0}onShow={() => setActiveIndex(0)}><ul><li>北京故宮</li><li>北京天安門</li><li>北京頤和園</li><li>北京王府井</li></ul></Panel><Paneltitle="已完成打卡地點"isActive={activeIndex === 1}onShow={() => setActiveIndex(1)}><ul><li>上海迪士尼</li><li>深圳世界之窗</li><li>廣州"小蠻腰"</li><li>廣州長隆</li></ul></Panel></div>);
};export default Accordion;// 定義 Panel 組件的 props 類型
interface PanelProps {title: string;children: React.ReactNode;isActive: boolean;onShow: () => void;
}// Panel 子組件
const Panel: React.FC<PanelProps> = ({ title, children, isActive, onShow }) => {return (<section style={{padding:"10px",background:"#e4e4e4",marginBottom:"10px"}}><h3 className="text-xl font-bold mb-2">{title}</h3>{isActive ? (<p className="text-gray-700">{children}</p>) : (<Buttonvariant="solid"color="primary"onClick={onShow}>顯示</Button>)}</section>);
};

在這里插入圖片描述
點擊下方顯示按鈕后
在這里插入圖片描述
這樣,我們就完成了對狀態的提升!將狀態移至公共父組件中可以讓你更好的管理這兩個面板。使用激活索引值代替之前的 是否顯示 標識確保了一次只能激活一個面板。而通過向下傳遞事件處理函數可以讓子組件修改父組件的狀態。
在這里插入圖片描述

每個狀態都對應唯一的數據源

在 React 應用中,很多組件都有自己的狀態。一些狀態可能“活躍”在葉子組件(樹形結構最底層的組件)附近,例如輸入框。另一些狀態可能在應用程序頂部“活動”。例如,客戶端路由庫也是通過將當前路由存儲在 React 狀態中,利用 props 將狀態層層傳遞下去來實現的!

**對于每個獨特的狀態,都應該存在且只存在于一個指定的組件中作為 state。**這一原則也被稱為擁有 “可信單一數據源”。它并不意味著所有狀態都存在一個地方——對每個狀態來說,都需要一個特定的組件來保存這些狀態信息。你應該 將狀態提升 到公共父級,或 將狀態傳遞 到需要它的子級中,而不是在組件之間復制共享的狀態。

你的應用會隨著你的操作而變化。當你將狀態上下移動時,你依然會想要確定每個狀態在哪里“活躍”。這都是過程的一部分!

摘要

  • 當你想要整合兩個組件時,將它們的 state 移動到共同的父組件中。
  • 然后在父組件中通過 props 把信息傳遞下去。
  • 最后,向下傳遞事件處理程序,以便子組件可以改變父組件的 state 。
  • 考慮該將組件視為“受控”(由 prop 驅動)或是“不受控”(由 state 驅動)是十分有益的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76888.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76888.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76888.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

階段性使用總結-通義靈碼

序言 前段時間用通義靈碼&#xff0c;參加了下數字中國閩江流域的比賽。https://www.dcic-china.com/competitions/10173 最后成績一般般&#xff0c;106名&#xff0c;大概有2000多人參加這題目&#xff0c;估計有一堆小號。 按照下面這個思路建模的&#xff0c;迭代了大概15…

游戲引擎學習第228天

對上次的內容進行回顧&#xff0c;并為今天的開發環節做鋪墊。 目前大部分功能我們已經完成了&#xff0c;唯一剩下的是一個我們知道存在但目前不會實際觸發的 bug。這個 bug 的本質是在某些線程仍然訪問一個已經被銷毀的游戲模式&#xff08;mode&#xff09;之后的狀態&…

游戲測試入門知識

高內聚指的是一個模塊或組件內部的功能應該緊密相關。這意味著模塊內的所有元素都應該致力于實現同一個目標或功能&#xff0c;并且該模塊應當盡可能獨立完成這一任務。 低耦合則是指不同模塊之間的依賴程度較低&#xff0c;即一個模塊的變化對其它模塊造成的影響盡可能小。理…

L1-2 種鉆石

題目 2019年10月29日&#xff0c;中央電視臺專題報道&#xff0c;中國科學院在培育鉆石領域&#xff0c;取得科技突破。科學家們用金剛石的籽晶片作為種子&#xff0c;利用甲烷氣體在能量作用下形成碳的等離子體&#xff0c;慢慢地沉積到鉆石種子上&#xff0c;一周“種”出了一…

基于開源技術生態的社群運營溫度化策略研究——以“開源鏈動2+1模式AI智能名片S2B2C商城小程序源碼”融合應用為例

摘要 在社交媒體與電商深度融合的背景下&#xff0c;社群運營的“溫度化”成為企業構建用戶忠誠度的核心命題。本文以康夏社群運營案例為切入點&#xff0c;結合“開源鏈動21模式AI智能名片S2B2C商城小程序源碼”技術架構&#xff0c;分析其通過開源技術實現情感聯結與商業價值…

編程技能:調試01,調試介紹

專欄導航 本節文章分別屬于《Win32 學習筆記》和《MFC 學習筆記》兩個專欄&#xff0c;故劃分為兩個專欄導航。讀者可以自行選擇前往哪個專欄。 &#xff08;一&#xff09;WIn32 專欄導航 上一篇&#xff1a;編程基礎&#xff1a;位運算07&#xff0c;右移 回到目錄 下一…

從零開始學A2A二 : A2A 協議的技術架構與實現

A2A 協議的技術架構與實現 學習目標 技術架構掌握 深入理解 A2A 協議的分層架構設計掌握各層次的功能和職責理解協議的工作原理和數據流 實現能力培養 能夠搭建基本的 A2A 服務端掌握客戶端開發方法實現智能體間的有效通信 架構設計理解 理解與 MCP 的本質區別掌握多智能體協…

UE5滾輪控制目標臂長度調整相機距離

UE5通過鼠標滾輪來控制攝像機目標臂長度 , 調整相機距離 看圖就行,不多說,照著連就完事了

python的strip()函數用法; 字符串切片操作

python的strip()函數用法 目錄 python的strip()函數用法代碼整體功能概述代碼詳細解釋1. `answer["output_text"]`2. `.strip()`3. `final_answer = ...`字符串切片操作:answer[start_index + len("Helpful Answer:"):].strip()整體功能概述代碼詳細解釋1…

云服務模式全知道:IaaS、PaaS、SaaS與DaaS深度解析

云服務模式詳解&#xff1a;IaaS、PaaS、SaaS與DaaS 在當今數字化快速發展的時代&#xff0c;云計算已經成為企業和開發者不可或缺的一部分。它提供了靈活的資源和服務&#xff0c;使得用戶可以根據自己的需求選擇最合適的解決方案。本文將詳細介紹四種主要的云服務模式&#…

AIDL 語言簡介

目錄 軟件包類型注釋導入AIDL 的后端AIDL 語言大致上基于 Java 語言。AIDL 文件不僅定義了接口本身,還會定義這個接口中用到的數據類型和常量。 軟件包 每個 AIDL 文件都以一個可選軟件包開頭,該軟件包與各個后端中的軟件包名稱相對應。軟件包聲明如下所示: package my.pac…

PINN:用深度學習PyTorch求解微分方程

神經網絡技術已在計算機視覺與自然語言處理等多個領域實現了突破性進展。然而在微分方程求解領域&#xff0c;傳統神經網絡因其依賴大規模標記數據集的特性而表現出明顯局限性。物理信息神經網絡(Physics-Informed Neural Networks, PINN)通過將物理定律直接整合到學習過程中&a…

程序化廣告行業(89/89):廣告創意審核的關鍵要點與實踐應用

程序化廣告行業&#xff08;89/89&#xff09;&#xff1a;廣告創意審核的關鍵要點與實踐應用 在程序化廣告這個充滿機遇與挑戰的領域&#xff0c;持續學習和知識共享是我們不斷進步的動力。一直以來&#xff0c;我都希望能和大家一同深入探索這個行業&#xff0c;今天讓我們聚…

【ES6新特性】Proxy進階實戰

&#x1f31f;ES6 Proxy終極指南&#xff1a;從攔截器到響應式框架實現&#x1f525; 一、&#x1f4a1; 為什么Proxy是革命性的&#xff1f;先看痛點場景 1.1 Object.defineProperty的局限 &#x1f62b; // Vue2響應式實現 let data { count: 0 }; Object.defineProperty(…

c++解決動態規劃

一、引言: 在我們學習了算法之后,我們一定遇到過貪心算法。而在貪心算法中就有著這樣一個經典的例子——湊錢。 Eg: 你有面額為10、5、1的紙幣,當你買菜時需要花費26元,請問需要最少的紙幣張數是多少。 當我們用貪心算法去解決這個問題的時候,我們…

Qwen 2.5 VL 多種推理方案

Qwen 2.5 VL 多種推理方案 flyfish 單圖推理 from modelscope import Qwen2_5_VLForConditionalGeneration, AutoTokenizer, AutoProcessor from qwen_vl_utils import process_vision_info import torchmodel_path "/media/model/Qwen/Qwen25-VL-7B-Instruct/"m…

機器視覺檢測Pin針歪斜應用

在現代電子制造業中&#xff0c;Pin針&#xff08;插針&#xff09;是連接器、芯片插座、PCB板等元器件的關鍵部件。如果Pin針歪斜&#xff0c;可能導致接觸不良、短路&#xff0c;甚至整機失效。傳統的人工檢測不僅效率低&#xff0c;還容易疲勞漏檢。 MasterAlign 機器視覺對…

經典算法問題解析:兩數之和與三數之和的Java實現

文章目錄 1. 問題背景2. 兩數之和&#xff08;Two Sum&#xff09;2.1 問題描述2.2 哈希表解法代碼實現關鍵點解析復雜度對比 3. 三數之和&#xff08;3Sum&#xff09;3.1 問題描述3.2 排序雙指針解法代碼實現關鍵點解析復雜度分析 4. 對比總結5. 常見問題解答6. 擴展練習 1. …

1022 Digital Library

1022 Digital Library 分數 30 全屏瀏覽 切換布局 作者 CHEN, Yue 單位 浙江大學 A Digital Library contains millions of books, stored according to their titles, authors, key words of their abstracts, publishers, and published years. Each book is assigned an u…

地理人工智能中位置編碼的綜述:方法與應用

以下是對論文 《A Review of Location Encoding for GeoAI: Methods and Applications》 的大綱和摘要整理&#xff1a; A Review of Location Encoding for GeoAI: Methods and Applications 摘要&#xff08;Summary&#xff09; 本文系統綜述了地理人工智能&#xff08;G…