跳到主要內容
+

API 設計方法

我們深入了解了 Material UI 的使用方式,而 v1 的重寫讓我們能夠完全重新思考組件 API。

API 設計很難,因為您可以使其看起來簡單,但實際上卻是具有欺騙性的複雜,或者使其實際上簡單但看起來很複雜。 @sebmarkbage

正如 Sebastian Markbage 指出的,沒有任何抽象概念優於錯誤的抽象概念。我們提供低階組件以最大化組合能力。

組合

您可能已經注意到在組件組合方面,API 中存在一些不一致之處。為了提供一些透明度,在設計 API 時,我們一直遵循以下規則

  1. 使用 children 屬性是使用 React 進行組合的慣用方式。
  2. 有時我們只需要有限的子組件組合,例如當我們不需要允許子組件順序排列時。在這種情況下,提供顯式的屬性使實作更簡單且效能更高;例如,Tab 組件接受 iconlabel 屬性。
  3. API 一致性很重要。

規則

除了上述組合權衡之外,我們還強制執行以下規則

展開

未明確記錄的組件屬性會被展開到根元素;例如,className 屬性會應用於根元素。

現在,假設您想要禁用 MenuItem 上的漣漪效果。您可以利用展開行為

<MenuItem disableRipple />

disableRipple 屬性將會這樣傳遞:MenuItem > ListItem > ButtonBase

原生屬性

我們避免記錄 DOM 支援的原生屬性,例如 className

CSS 類別

所有組件都接受 classes 屬性來自訂樣式。類別設計回答了兩個約束條件:使類別結構盡可能簡單,同時又足以實作 Material Design 指南。

  • 應用於根元素的類別始終稱為 root
  • 所有預設樣式都分組在一個類別中。
  • 應用於非根元素的類別會以元素名稱作為前綴,例如 Dialog 組件中的 paperWidthXs
  • 布林屬性應用的變體沒有前綴,例如 rounded 屬性應用的 rounded 類別。
  • 枚舉屬性應用的變體前綴,例如 color="primary" 屬性應用的 colorPrimary 類別。
  • 一個變體具有一個層級的特異性colorvariant 屬性被視為變體。樣式特異性越低,覆蓋就越簡單。
  • 我們提高了變體修飾符的特異性。對於偽類別(:hover:focus 等),我們已經必須這樣做。這允許更多的控制,但代價是更多的樣板程式碼。希望這也更直觀。
const styles = {
  root: {
    color: green[600],
    '&$checked': {
      color: green[500],
    },
  },
  checked: {},
};

巢狀組件

組件內部的巢狀組件具有

  • 它們自己的扁平化屬性,當這些屬性是頂層組件抽象的關鍵時,例如 Input 組件的 id 屬性。
  • 它們自己的 xxxProps 屬性,當使用者可能需要調整內部渲染方法的子組件時,例如,在內部使用 Input 的組件上公開 inputPropsInputProps 屬性。
  • 它們自己的 xxxComponent 屬性,用於執行組件注入。
  • 它們自己的 xxxRef 屬性,當您可能需要執行命令式操作時,例如,公開 inputRef 屬性以訪問 Input 組件上的原生 input。這有助於回答問題 「我該如何訪問 DOM 元素?」

屬性命名

  • 布林值

    • 布林屬性的預設值應為 false。這樣可以實現更好的簡寫表示法。考慮一個預設啟用的輸入範例。您應該如何命名控制此狀態的屬性?它應該被稱為 disabled

      <Input enabled={false} /><Input disabled />
      
    • 如果布林值的名稱是一個單詞,它應該是一個形容詞或名詞,而不是動詞。這是因為屬性描述的是狀態而不是動作。例如,輸入屬性可以由狀態控制,而狀態不會用動詞描述

      const [disabled, setDisabled] = React.useState(false);<Input disable={disabled} /><Input disabled={disabled} />
      

受控組件

大多數受控組件都由 valueonChange 屬性控制。open / onClose / onOpen 組合也用於顯示相關狀態。在事件較多的情況下,名詞在前,動詞在後——例如:onPageChangeonRowsChange

布林值 vs. 枚舉

有兩種選項可以為組件的變體設計 API:使用布林值;或使用枚舉。例如,我們以具有不同類型的按鈕為例。每個選項都有其優缺點

  • 選項 1 布林值

    type Props = {
      contained: boolean;
      fab: boolean;
    };
    

    此 API 啟用簡寫表示法:<Button><Button contained /><Button fab />

  • 選項 2 枚舉

    type Props = {
      variant: 'text' | 'contained' | 'fab';
    };
    

    此 API 更為冗長:<Button><Button variant="contained"><Button variant="fab">

    但是,它可以防止使用無效的組合,限制公開的屬性數量,並且可以輕鬆地在未來支援新值。

Material UI 組件根據以下規則結合使用了這兩種方法

  • 當需要 2 個可能值時,使用布林值
  • 當需要 > 2 個可能值時,或者如果未來可能需要額外的可能值時,使用枚舉

回到之前的按鈕範例;由於它需要 3 個可能值,我們使用枚舉

Ref

ref 被轉發到根元素。這表示,在不透過 component 屬性更改渲染的根元素的情況下,它會被轉發到組件渲染的最外層 DOM 元素。如果您透過 component 屬性傳遞不同的組件,則 ref 將會附加到該組件。

詞彙表

  • host component:在 react-dom 上下文中的 DOM 節點類型,例如 'div'。另請參閱 React Implementation Notes
  • host element:在 react-dom 上下文中的 DOM 節點,例如 window.HTMLDivElement 的實例。
  • outermost:從上到下讀取組件樹時的第一個組件,即廣度優先搜尋。
  • root component:渲染 host component 的最外層組件。
  • root element:渲染 host component 的最外層元素。