最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談React 組件的組合模式之道(Composition Pattern)

 更新時(shí)間:2025年11月30日 16:17:12   作者:iMonster  
本文主要介紹了React組件的組合模式之道(Composition Pattern),通過將復(fù)雜組件拆分為多個(gè)小、職責(zé)單一的子組件,并通過Context共享狀態(tài),可以避免單體組件的陷阱,感興趣的可以了解一下

基于 React Universe Conf 2025 中 Fernando Rojo 的演講《Composition is all you need》,以下是關(guān)于如何使用**組合模式(Composition Pattern)**重構(gòu)復(fù)雜 React 組件的教程和代碼總結(jié)。

React 組件的組合模式之道 (Composition Pattern)

1. 核心問題:單體組件的陷阱 (The Monolith Trap)

在開發(fā)初期,我們通常創(chuàng)建一個(gè)簡單的組件(如 Composer 輸入框)。隨著需求增加(支持多態(tài)、編輯模式、轉(zhuǎn)發(fā)模式等),我們往往通過添加 Boolean 屬性來控制功能。

反模式代碼示例:

// ? 典型的“單體”組件,充滿條件判斷
function Composer({ 
  onSubmit, 
  isThread, 
  isEditingMessage, 
  initialText, 
  onCancel 
}) {
  return (
    <div className="composer">
      {/* 只有非編輯模式才支持拖拽 */}
      {!isEditingMessage && <DropZone />}
      
      <Header />
      <Input defaultValue={initialText} />
      
      {/* 線程模式下的額外選項(xiàng) */}
      {isThread && <Checkbox label="Also send to channel" />}
      
      <Footer>
        {/* 只有非編輯模式才顯示附件按鈕 */}
        {!isEditingMessage && <AttachmentButton />}
        
        {/* 提交按鈕邏輯復(fù)雜 */}
        {isEditingMessage ? (
           <>
             <Button onClick={onCancel}>Cancel</Button>
             <Button onClick={onSubmit}>Save</Button>
           </>
        ) : (
           <Button onClick={onSubmit}>Send</Button>
        )}
      </Footer>
    </div>
  );
}

缺點(diǎn): 代碼難以維護(hù),條件渲染(Ternary Hell)泛濫,且容易出現(xiàn)不可能的狀態(tài)組合。

2. 解決方案:組合模式 (Composition)

與其通過屬性(Props)告訴組件做什么,不如通過子組件(Children)直接構(gòu)建組件。這種方式類似于 Radix UI 的設(shè)計(jì)理念。

我們將大組件拆分為多個(gè)小的、職責(zé)單一的子組件,并通過 Context 共享狀態(tài)。

基礎(chǔ)架構(gòu)代碼

// 1. 創(chuàng)建 Context
const ComposerContext = createContext(null);

// 2. Provider 組件:管理狀態(tài)和對(duì)外接口
const ComposerProvider = ({ children, state, actions, meta }) => {
  return (
    <ComposerContext.Provider value={{ state, actions, meta }}>
      {children}
    </ComposerContext.Provider>
  );
};

// 3. 子組件:消費(fèi) Context
const ComposerInput = () => {
  const { state, actions } = useContext(ComposerContext);
  return (
    <input 
      value={state.text} 
      onChange={(e) => actions.update(e.target.value)} 
    />
  );
};

// ... 其他子組件 (Composer.Header, Composer.Footer, etc.)

3. 實(shí)戰(zhàn)重構(gòu):構(gòu)建不同的 Composer

通過組合,我們可以在不修改內(nèi)部邏輯的情況下,構(gòu)建出完全不同的 UI 變體。

場景 A:基礎(chǔ)頻道輸入框 (Channel Composer)

function ChannelComposer() {
  // 使用自定義 Hook 獲取全局頻道邏輯
  const { state, actions } = useChannelLogic(); 

  return (
    <Composer.Provider state={state} actions={actions}>
      <Composer.DropZone />
      <Composer.Frame>
        <Composer.Header />
        <Composer.Input />
        <Composer.Footer>
          {/* 使用封裝好的通用操作組 */}
          <Composer.CommonActions /> 
          <Composer.SubmitButton />
        </Composer.Footer>
      </Composer.Frame>
    </Composer.Provider>
  );
}

場景 B:編輯消息輸入框 (Edit Message Composer)

需求差異:

  1. 不需要拖拽上傳 (DropZone)。
  2. 底部按鈕不同(取消/保存)。
  3. 某些操作按鈕不可見(如附件)。

組合實(shí)現(xiàn): 我們只需要不渲染不需要的組件,并替換底部的按鈕即可,無需任何 Boolean 屬性。

function EditMessageComposer({ messageId, initialText, onCancel }) {
  const { state, actions } = useEditMessageLogic(messageId, initialText);

  return (
    <Composer.Provider state={state} actions={actions}>
      {/* 移除 DropZone */}
      <Composer.Frame>
        <Composer.Header />
        <Composer.Input />
        <Composer.Footer>
          {/* 手動(dòng)列出需要的 Action,而不是用通用的 */}
          <Composer.FormatText />
          <Composer.Emoji />
          
          {/* 自定義底部按鈕布局 */}
          <div className="flex gap-2">
            <Button onClick={onCancel}>Cancel</Button>
            <Button onClick={actions.submit}>Save</Button>
          </div>
        </Composer.Footer>
      </Composer.Frame>
    </Composer.Provider>
  );
}

4. 進(jìn)階技巧:狀態(tài)提升與解耦 (Lift Your State)

這是該演講最核心的觀點(diǎn)。狀態(tài)管理應(yīng)該與 UI 組件解耦。

Composer 的 UI 組件(Input, Footer 等)不應(yīng)該知道狀態(tài)是來自于 useState(本地狀態(tài))還是 useGlobalStore(全局同步狀態(tài))。它們只負(fù)責(zé)渲染 Provider 提供的數(shù)據(jù)。

場景 C:轉(zhuǎn)發(fā)消息 (Forward Message)

復(fù)雜點(diǎn):

  1. 這是一個(gè)模態(tài)框(Modal)。
  2. 提交按鈕在 Composer 外部(Modal 的 Footer)。
  3. 狀態(tài)是臨時(shí)的(Ephemeral),不需要同步到服務(wù)器。

代碼實(shí)現(xiàn):

function ForwardMessageDialog() {
  // 1. 狀態(tài)提升:在父組件控制狀態(tài)
  const [text, setText] = useState("");
  const inputRef = useRef(null);

  // 定義符合 Provider 接口的 state 和 actions
  const state = { text };
  const actions = { 
    update: setText, 
    submit: () => console.log("Forwarding:", text) 
  };

  return (
    <Dialog>
      {/* 2. 將本地狀態(tài)注入 Provider */}
      <Composer.Provider state={state} actions={actions} meta={{ inputRef }}>
        
        {/* UI 部分 */}
        <Composer.Frame>
          <Composer.Input /> 
          <Composer.Footer>
             {/* 只有少量的操作按鈕 */}
             <Composer.Emoji />
          </Composer.Footer>
        </Composer.Frame>

        {/* 3. 外部按鈕也可以消費(fèi)同一個(gè) Context */}
        <Dialog.Footer>
           <CopyLinkButton />
           {/* 這個(gè)按鈕在 Composer 外部,但能觸發(fā)提交 */}
           <ForwardButton /> 
        </Dialog.Footer>

      </Composer.Provider>
    </Dialog>
  );
}

// 外部按鈕實(shí)現(xiàn)
const ForwardButton = () => {
  // 因?yàn)楸话?Composer.Provider 內(nèi),依然可以訪問 context
  const { actions } = useContext(ComposerContext);
  return <Button onClick={actions.submit}>Forward</Button>;
}

總結(jié):為什么要這樣做?

  1. 消除“布爾地獄”: 不再需要傳遞 isEditing={true}、isForwarding={true} 并在組件深處做判斷。需要什么功能,就渲染什么組件。
  2. 狀態(tài)靈活性: 同一套 UI 組件可以配合 useState(本地)、Redux/Zustand(全局)甚至 Ref 一起工作,只要通過 Provider 傳入即可。
  3. 可維護(hù)性: 當(dāng)需要在“轉(zhuǎn)發(fā)”功能中修改按鈕樣式時(shí),你只需要修改 ForwardMessageDialog,完全不會(huì)影響到“頻道聊天”的代碼。
  4. AI 友好: 這種結(jié)構(gòu)化、聲明式的代碼更容易被 AI 理解和生成,減少了 AI 產(chǎn)生幻覺(Hallucination)或邏輯錯(cuò)誤的概率。

一句話總結(jié): 不要把所有的邏輯塞進(jìn)一個(gè)組件里。提升你的狀態(tài) (Lift your state),組合你的內(nèi)部組件 (Compose your internals)。

到此這篇關(guān)于淺談React 組件的組合模式之道(Composition Pattern)的文章就介紹到這了,更多相關(guān)React 組件組合內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React?在非組件環(huán)境切換路由的方法

    React?在非組件環(huán)境切換路由的方法

    這篇文章主要介紹了React?在非組件環(huán)境切換路由的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-10-10
  • React實(shí)現(xiàn)原生APP切換效果

    React實(shí)現(xiàn)原生APP切換效果

    最近需要使用 Hybrid 的方式開發(fā)一 個(gè) APP,交互和原生 APP 相似并且需要 IM 通信,本文給大家介紹了使用React實(shí)現(xiàn)原生APP切換效果,文中通過代碼示例講解的非常詳細(xì),感興趣的小伙伴跟著小編一起來看看吧
    2025-01-01
  • React中setTimeout獲取不到最新State值的原因及解決方案

    React中setTimeout獲取不到最新State值的原因及解決方案

    在 React 開發(fā)中,我們常常需要在異步操作中訪問組件的 State,然而,由于 React 的閉包機(jī)制和異步更新特性,setTimeout?中可能會(huì)獲取到過時(shí)的 State 值,本文將深入解析這一現(xiàn)象的原因,并提供多種解決方案,需要的朋友可以參考下
    2025-10-10
  • react項(xiàng)目自行配置熱更新的實(shí)現(xiàn)

    react項(xiàng)目自行配置熱更新的實(shí)現(xiàn)

    本文主要介紹了react項(xiàng)目自行配置熱更新的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-11-11
  • vite?+?react?+typescript?環(huán)境搭建小白入門教程

    vite?+?react?+typescript?環(huán)境搭建小白入門教程

    這篇文章主要介紹了vite?+?react?+typescript?環(huán)境搭建小白入門教程,本文通過示例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • React父子組件間的傳值的方法

    React父子組件間的傳值的方法

    在單頁面里面,父子組件傳值是比較常見的,這篇文章主要介紹了React父子組件間的傳值的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-11-11
  • React中不適當(dāng)?shù)腍ooks使用問題及解決方案

    React中不適當(dāng)?shù)腍ooks使用問題及解決方案

    在 React 開發(fā)中,Hooks 提供了一種強(qiáng)大的方式來管理組件的狀態(tài)和生命周期,然而,不恰當(dāng)?shù)?nbsp;Hooks 使用可能會(huì)導(dǎo)致組件行為異常、性能問題或難以調(diào)試的錯(cuò)誤,本文將探討 React 中常見的不適當(dāng) Hooks 使用問題,并提供解決方案,需要的朋友可以參考下
    2025-03-03
  • 詳解Immutable及 React 中實(shí)踐

    詳解Immutable及 React 中實(shí)踐

    Immutable 可以給 React 應(yīng)用帶來數(shù)十倍的提升,也有人說 Immutable 的引入是近期 JavaScript 中偉大的發(fā)明,因?yàn)橥?React 太火,它的光芒被掩蓋了。這篇文章主要介紹了Immutable及 React 中的實(shí)踐,需要的朋友可以參考下
    2018-03-03
  • React使用UI(Ant?Design)框架的詳細(xì)過程

    React使用UI(Ant?Design)框架的詳細(xì)過程

    Ant?Design主要用于中后臺(tái)系統(tǒng)的使用,它提供了豐富的組件和工具,可以幫助開發(fā)人員快速構(gòu)建出美觀、易用的界面,同時(shí),Ant?Design還提供了詳細(xì)的文檔和示例,方便開發(fā)者學(xué)習(xí)和使用,這篇文章主要介紹了React使用UI(Ant?Design)框架,需要的朋友可以參考下
    2023-12-12
  • 一百多行代碼實(shí)現(xiàn)react拖拽hooks

    一百多行代碼實(shí)現(xiàn)react拖拽hooks

    這篇文章主要介紹了一百多行代碼實(shí)現(xiàn)react拖拽hooks,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03

最新評(píng)論

雷山县| 和平县| 百色市| 阳原县| 潍坊市| 南丹县| 璧山县| 什邡市| 涞源县| 托克逊县| 梅河口市| 呼玛县| 搜索| 石嘴山市| 昂仁县| 白玉县| 灵璧县| 肃宁县| 锦屏县| 东山县| 晋城| 伊宁县| 湛江市| 阿城市| 个旧市| 全州县| 法库县| 广安市| 多伦县| 浦北县| 花莲县| 平度市| 陕西省| 蓬溪县| 额尔古纳市| 晋江市| 改则县| 巧家县| 临江市| 屏南县| 靖西县|