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

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

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

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

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

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

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

反模式代碼示例:

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

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

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

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

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

基礎架構代碼

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

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

// 3. 子組件:消費 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. 實戰(zhàn)重構:構建不同的 Composer

通過組合,我們可以在不修改內部邏輯的情況下,構建出完全不同的 UI 變體。

場景 A:基礎頻道輸入框 (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. 某些操作按鈕不可見(如附件)。

組合實現: 我們只需要不渲染不需要的組件,并替換底部的按鈕即可,無需任何 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>
          {/* 手動列出需要的 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. 進階技巧:狀態(tài)提升與解耦 (Lift Your State)

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

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

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

復雜點:

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

代碼實現:

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. 外部按鈕也可以消費同一個 Context */}
        <Dialog.Footer>
           <CopyLinkButton />
           {/* 這個按鈕在 Composer 外部,但能觸發(fā)提交 */}
           <ForwardButton /> 
        </Dialog.Footer>

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

// 外部按鈕實現
const ForwardButton = () => {
  // 因為被包在 Composer.Provider 內,依然可以訪問 context
  const { actions } = useContext(ComposerContext);
  return <Button onClick={actions.submit}>Forward</Button>;
}

總結:為什么要這樣做?

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

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

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

相關文章

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

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

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

    React實現原生APP切換效果

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

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

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

    react項目自行配置熱更新的實現

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

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

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

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

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

    React中不適當的Hooks使用問題及解決方案

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

    詳解Immutable及 React 中實踐

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

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

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

    一百多行代碼實現react拖拽hooks

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

最新評論

诸城市| 福鼎市| 独山县| 余干县| 南昌市| 德阳市| 武清区| 丰城市| 台湾省| 清镇市| 嘉兴市| 通江县| 德钦县| 合水县| 太保市| 和田县| 务川| 漾濞| 张家口市| 边坝县| 隆林| 甘南县| 齐齐哈尔市| 仙游县| 玉林市| 永新县| 喀什市| 长寿区| 来宾市| 通辽市| 岗巴县| 伊金霍洛旗| 郧西县| 密云县| 上饶县| 龙陵县| 彭泽县| 临泽县| 繁昌县| 重庆市| 上高县|