優秀元件設計的關鍵:自私原則"

前端小智發表於2023-03-29
本文首發於微信公眾號:大遷世界, 我的微信:qq449245884,我會第一時間和你分享前端行業趨勢,學習途徑等等。
更多開源作品請看 GitHub https://github.com/qq449245884/xiaozhi ,包含一線大廠面試完整考點、資料以及我的系列文章。
當把元件從設計轉化為開發時,常常會發現一些屬性與內容有關,而與元件本身無關。這種考慮周到的元件設計方法導致了複雜的屬性、更陡峭的學習曲線和最終的技術債務。然而,避免這些陷阱的關鍵是自私或自我利益為中心的元件設計。

在開發新功能時,是什麼決定了現有元件是否可行?當一個元件不能使用時,這究竟意味著什麼?

該元件在功能上是否沒有做它所期望的事情,比如一個標籤系統沒有切換到正確的皮膚?或者它太死板,不能支援設計的內容,比如一個在內容之後而不是之前有圖示的按鈕?或者是它太過預設和結構化,無法支援輕微的變體,比如一個一直有標題部分的模態,現在需要一個沒有標題的變體?

這就是元件的生活。很多時候,它們是為了一個狹窄的目標而構建的,然後匆忙地為一個接一個的小變化進行擴充套件,直到不再可行。在這個時候,會建立一個新元件,技術債務增長,入職學習曲線變得更陡峭,程式碼庫的可維護性變得更具挑戰性。

這僅僅是元件不可避免的生命週期嗎?還是這種情況可以避免?最重要的是,如果可以避免,怎麼做?

自私。或者說,自利。更好的說法可能是兩者兼而有之。

很多時候,元件過於體貼。它們對彼此太體貼了,尤其是對它們自己的內容太體貼了。為了建立能夠隨著產品擴充套件的元件,關鍵是自私地關注自己的利益——冷酷、自戀、世界環繞著我旋轉的自私。

本文並不打算解決自利和自私之間幾百年的爭論。坦白說,我沒有資格參與任何哲學辯論。然而,本文要做的是證明構建自私元件對其他元件、設計師、開發者和使用你內容的人來說是最有利的。事實上,自私的元件在它們周圍創造瞭如此多的好處,以至於你幾乎可以說它們是無私的。

注意:本文中的所有程式碼示例和演示都將基於React和TypeScript。然而,這些概念和模式是與框架無關的。

考慮的迭代

也許,展示一個體貼的元件的最好方式是透過走過一個元件的生命週期。我們將能夠看到它們是如何開始時很小,功能很強,但一旦設計發展起來就會變得很笨重。每一次迭代都會使元件進一步陷入困境,直到產品的設計和需求超過了元件本身的能力。

讓我們考慮一下謙虛的Button元件。它具有欺騙性的複雜性,而且經常被困在考慮模式中,因此,是一個很好的工作例項。

迭代1

雖然這些樣本設計相當簡陋,比如沒有顯示各種:hover:focus:disabled狀態,但它們確實展示了一個有兩種顏色主題的簡單按鈕。

image.png

乍一看,所產生的Button元件有可能和設計一樣是赤裸裸的。

// 首先,從React擴充套件原生HTML按鈕屬性,如onClick和disabled。
type ButtonProps = React.ComponentPropsWithoutRef<"button"> & {
  text: string;
  theme: 'primary' | 'secondary';
}
<Button
  onClick={someFunction}
  text="Add to cart"
  theme="primary"
/>

有可能,甚至有可能,我們都見過這樣的一個Button元件。也許我們甚至自己也做過這樣的一個。有些名字可能不一樣,但 props 或Button的API大致上是一樣的。

為了滿足設計的要求,Button 為 themetext 定義了 props 。這第一個迭代工作,滿足了設計和產品的當前需求。

然而,設計和產品的當前需求很少是最終需求。當下次設計迭代時,新增到購物車的按鈕現在需要一個圖示。

迭代2

在驗證了產品的使用者介面後,決定在新增到購物車的按鈕上增加一個圖示,這將是有益的。不過,設計人員解釋說,不是每個按鈕都會包括一個圖示。

image.png

回到我們的Button元件,它的 props 可以用一個可選的 icon 來擴充套件,該 props 對映到一個圖示的名稱,以便有條件地渲染。

type ButtonProps = {
  theme: 'primary' | 'secondary';
  text: string;
  icon?: 'cart' | '...all-other-potential-icon-names';
}
<Button
  theme="primary"
  onClick={someFunction}
  text="Add to cart"
  icon="cart"
/>

嗚呼!危機解除了。

有了新的 icon prop,Button 現在可以支援帶或不帶圖示的變體。當然,這假定圖示總是顯示在文字的末尾,但出乎意料的是,在設計下一次迭代時,情況並非如此。

迭代3

以前的Button元件的實現包括文字末尾的圖示,但新的設計要求圖示可以選擇放在文字的開頭。單一的 icon prop 將不再適合最新設計要求的需要。

image.png

有幾個不同的方向可以用來滿足這個新產品的要求。也許可以給Button新增一個iconPosition prop 。但如果需要在兩邊都有一個圖示呢?也許我們的Button元件可以領先於這個假設的要求,對 prop 做一些改變。

單一的 icon prop 將不再適合產品的需要,所以它被移除。取而代之的是兩個新 prop,iconAtStarticonAtEnd

type ButtonProps = {
  theme: 'primary' | 'secondary' | 'tertiary';
  text: string;
  iconAtStart?: 'cart' | '...all-other-potential-icon-names';
  iconAtEnd?: 'cart' | '...all-other-potential-icon-names';
}

在重構程式碼庫中Button的現有用途以使用新的 props ,另一個危機被避免了。現在,Button有了一些靈活性。所有這些都是硬編碼的,並被包裝在元件本身的條件中,但可以肯定的是,UI不知道的東西不會傷害它。

到目前為止,Button圖示一直是與文字相同的顏色。這似乎是合理的,也是一個可靠的預設值,但讓我們透過定義一個具有對比色的圖示的變體來給這個運轉良好的元件帶來麻煩。

迭代4

為了提供一種反饋感,這個確認使用者介面階段被設計為在物品被成功新增到購物車時臨時顯示。

也許這個時候,開發團隊會選擇對產品需求進行反擊。但儘管如此,還是決定繼續推進為Button圖示提供顏色靈活性。

image.png

同樣,可以採取多種方法來解決這個問題。也許一個iconClassName prop 被傳遞到 Button中,以便對圖示的外觀有更好的控制。但是,還有其他的產品開發重點,因此,只能做一個快速修復。

因此,一個 iconColor prop 被新增到 Butto n中。

type ButtonProps = {
  theme: 'primary' | 'secondary' | 'tertiary';
  text: string;
  iconAtStart?: 'cart' | '...all-other-potential-icon-names';
  iconAtEnd?: 'cart' | '...all-other-potential-icon-names';
  iconColor?: 'green' | '...other-theme-color-names';
}

隨著快速修復的到位,Button圖示現在可以採用與文字不同的風格。UI可以提供所設計的確認,而產品可以再次向前推進。

當然,隨著產品要求的不斷增長和擴大,他們的設計也在不斷髮展。

迭代5

在最新的設計中,Button現在必須只用一個圖示來使用。這可以用幾種不同的方法來完成,然而,所有這些方法都需要進行一定程度的重構。

image.png

也許一個新的IconButton元件被建立,將所有其他的按鈕邏輯和樣式重複到兩個地方。或者,這些邏輯和樣式被集中起來,在兩個元件中共享。然而,在這個例子中,開發團隊決定將所有的變體放在同一個Button元件中。

相反, text prop 被標記為可選。這可以像在 props 中標記為可選一樣快速,但如果有任何期望文字存在的邏輯,可能需要額外的重構。

但是問題來了,如果Button只有一個圖示,應該使用哪個圖示道具?iconAtStarticonAtEnd都沒有適當地描述Button。最終,我們決定把原來的圖示道具帶回來,用於僅有圖示的變體。

type ButtonProps = {
  theme: 'primary' | 'secondary' | 'tertiary';
  iconAtStart?: 'cart' | '...all-other-potential-icon-names';
  iconAtEnd?: 'cart' | '...all-other-potential-icon-names';
  iconColor?: 'green' | '...other-theme-color-names';
  icon?: 'cart' | '...all-other-potential-icon-names';
  text?: string;
}

現在,Button 的API越來越令人困惑。也許在元件中留有一些註釋,以解釋何時和何時不使用特定的 prop,但學習曲線越來越陡峭,出錯的可能性也越來越大。

例如,如果不給 ButtonProps 型別增加巨大的複雜性,就無法阻止一個人同時使用 icon 和 text prop。這可能會破壞使用者介面,或者在Button元件本身中用更復雜的條件來解決。此外, icon prop 也可以與iconAtStartIconAtEnd prop 中的一個或兩個一起使用。同樣,這可能會破壞使用者介面,或者在元件內用更多的條件層來解決。

我們心愛的Button在這一點上已經變得相當難以管理了。希望產品已經達到一個穩定點,不會再有新的變化或要求發生。永遠。

迭代6

這麼說來,永遠不會有任何變化了。?

image.png

Button 的下一個也是最後一個迭代是傳說中壓垮駱駝的那根稻草。在新增到購物車的按鈕中,如果當前物品已經在購物車中,我們想在按鈕上顯示其中的數量。從表面上看,這是一個直接的變化,即動態地建立 text prop 字串。但是這個元件被打破了,因為當前商品數量需要一個不同的字型重量和下劃線。因為Button只接受純文字字串,沒有其他子元素,所以這個元件不再工作。

這個設計如果是第二次迭代的話,會不會導致按鈕失效呢?也許不會。那時元件和程式碼庫都還很年輕。但是到目前為止,程式碼庫已經增長了很多,要為這個需求進行重構簡直就像是攀登高峰。

這時可能會發生以下事情之一。

  • 做一個更大的重構,把Button從一個 text prop 移到接受 children 或接受一個元件或標記作為 text
  • 該 Button 被分割成一個單獨的 AddToCart 按鈕,有一個更嚴格的 API,專門用於這一個用例。這也是將任何按鈕的邏輯和樣式複製到多個地方,或者將它們提取到一個集中的檔案中,以便到處共享。
  • 按鈕被棄用,並建立了一個 ButtonNew 元件,分裂了程式碼庫,引入了技術債務,並增加了入職學習曲線。

兩種結果都不理想。

那麼,"按鈕"元件在哪裡出了問題?

分享是一種損害

HTML button 元素的職責究竟是什麼?縮小這個答案將照亮之前Button元件所面臨的問題。

原生的 HTML button元素的職責不過如此:

  1. 顯示,沒有意見,無論什麼內容被傳入它。
  2. 處理本地功能和屬性,如onClickdisabled

是的,每個瀏覽器對按鈕元素的外觀和顯示內容都有自己的版本,但CSS重置通常被用來剝奪這些意見。因此,按鈕元素歸根結底只是一個用於觸發事件的功能性容器而已。

對按鈕內的任何內容進行格式化不是按鈕的責任,而是內容本身的責任。按鈕不應該關心。按鈕不應該分擔對其內容的責任。

體貼的元件設計的核心問題是,元件 prop 定義了內容而不是元件本身。

在以前的 Button 元件中,第一個主要限制是 text prop 。從第一次迭代開始,就對Button的內容進行了限制。雖然 text prop 符合那個階段的設計,但它立即偏離了本地HTML按鈕的兩個核心職責。它立即迫使Button意識到並對其內容負責。

在接下來的迭代中,圖示被引入。雖然在Button中加入一個有條件的圖示似乎很合理,但這樣做也偏離了按鈕的核心職責。這樣做限制了該元件的使用情況。在後來的迭代中,圖示需要在不同的位置可用,而Button的 prop 也被迫擴充套件到圖示的樣式。

當元件對它所顯示的內容負責時,它需要一個能適應所有內容變化的API。最終,這個API將被打破,因為內容將永遠永遠地改變。

介紹一下團隊中的我#。

在所有團隊運動中都有一句格言:"團隊中沒有'我'"。雖然這種心態很高尚,但一些最偉大的個人運動員卻體現了其他想法。

邁克爾-喬丹用他自己的觀點做出了著名的回應:"勝利中有一個'我'"。已故的科比-布萊恩特也有類似的想法,"[團隊]裡有一個'M-E'"。

我們最初的Button元件是一個團隊成員。它分擔了其內容的責任,直到它達到廢棄的地步。按鈕如何透過體現 "團隊中的M-E "的態度來避免這種限制?

我,我自己,還有UI

當元件對它所顯示的內容負責時,它就會崩潰,因為內容將永遠永遠地改變。

一個自私的元件設計方法會如何改變我們最初的按鈕?

牢記HTML按鈕元素的兩個核心職責,我們的Button元件的結構會立即發生變化。

// 首先,從React擴充套件原生HTML按鈕屬性,如onClick和disabled
type ButtonProps = React.ComponentPropsWithoutRef<"button"> & {
  theme: 'primary' | 'secondary' | 'tertiary';
}
<Button
  onClick={someFunction}
  theme="primary"
>
  <span>Add to cart</span>
</Button>

透過去掉原來的 text prop 來代替無限的 children,Button能夠與它的核心職責保持一致。現在,Button可以作為一個觸發事件的容器而已。

透過將Button轉移到支援子內容的本地方法,不再需要各種與圖示相關的道具。現在,一個圖示可以在Button的任何地方呈現,無論其大小和顏色如何。也許各種與圖示相關的道具可以被提取到他們自己的自私的 Icon 元件中。

<Button
  onClick={someFunction}
  theme="primary"
>
  <Icon name="cart" />
  <span>Add to cart</span>
</Button>

隨著特定內容的 prop 從 Button 中移除,它現在可以做所有自私的角色最擅長的事情,即思考自己。

// First, extend native HTML button attributes like onClick and disabled from React.
type ButtonProps = React.ComponentPropsWithoutRef<"button"> & {
  size: 'sm' | 'md' | 'lg';
  theme: 'primary' | 'secondary' | 'tertiary';
  variant: 'ghost' | 'solid' | 'outline' | 'link'
}

有了專門針對自身的API和獨立的內容,Button現在是一個可維護的元件。自身的 props 使學習曲線最小化和直觀化,同時為各種Button的使用案例保留了極大的靈活性。

按鈕圖示現在可以放置在內容的兩端:

<Button
  onClick={someFunction}
  size="md"
  theme="primary"
  variant="solid"
>
  <Box display="flex" gap="2" alignItems="center">
    <span>Add to cart</span>
    <Icon name="cart" />
  </Box>
</Button>

或者,一個Button可以只有一個圖示:

<Button
  onClick={someFunction}
  size="sm"
  theme="secondary"
  variant="solid"
>
  <Icon name="cart" />
</Button>

然而,一個產品可能會隨著時間的推移而演變,而自私的元件設計可以提高與之一起演變的能力。讓我們超越Button,進入自私的元件設計的基石。

自私設計的關鍵

與創造一個虛構的人物時一樣,最好是向讀者展示,而不是告訴他們,他們是自私的。透過閱讀人物的思想和行動,可以瞭解他們的個性和特徵。元件設計也可以採取同樣的方法。

但是,我們究竟如何在一個元件的設計和使用中表明它是自私的?

HTML驅動元件設計

很多時候,元件是作為本地HTML元素的直接抽象而構建的,比如 buttonimg。在這種情況下,讓本地HTML元素來驅動元件的設計。

具體來說,如果本地HTML元素接受子元素,那麼抽象的元件也應該接受。一個元件的每一個方面如果偏離了它的原生元素,就必須重新學習。

當我們最初的Button元件因為不支援子內容而偏離了按鈕元素的原生行為時,它不僅變得僵硬,而且需要轉變思維模式才能使用該元件。

在HTML元素的結構和定義方面,已經投入了大量的時間和精力。輪子不需要每次都被重新發明。

children 自食其力

如果你讀過《蠅王》,你就知道當一群孩子被迫自食其力時,會有多危險。然而,在自私的元件設計案例中,我們要做的正是這樣。

正如我們最初的Button元件所顯示的那樣,它越是試圖對其內容進行樣式設計,它就越是僵硬和複雜。當我們去掉這個責任時,這個元件就能做得更多,但卻少了很多。

許多元素只不過是語義上的容器而已。我們並不經常期望一個章節元素能夠為其內容提供樣式。一個按鈕元素只是一個非常特殊的語義容器型別。當把它抽象為一個元件時,同樣的方法可以適用。

元件是單一的重點

把自私的元件設計想象成安排一堆糟糕的第一次約會。一個元件的 prop 就像完全以他們和他們的直接責任為中心的對話。

我看起來怎麼樣?

prop 需要滿足元件的自我要求。在我們重構的Button例子中,我們用大小、主題和變體等 prop做到了這一點。

我在做什麼?

一個元件應該只對它,而且是它自己正在做的事情感興趣。同樣,在我們重構的Button元件中,我們用onClick prop來做這個。就Button而言,如果在其內容的某個地方有另一個點選事件,那是內容的問題。按鈕並不關心。

我的下一站是什麼時候,在哪裡?

任何噴射性的旅行者都會很快談論他們的下一個目的地。對於像模態、抽屜和工具提示這樣的元件來說,它們何時何地也同樣重要。像這樣的元件並不總是在DOM中呈現的。這意味著,除了知道它們的外觀和作用之外,它們還需要知道何時何地。換句話說,這可以用isShownposition這樣的props來描述。

構圖為王

一些元件,如模版和抽屜,往往可以包含不同的佈局變化。例如,有些模版會顯示一個標題欄,而其他模版則沒有。一些抽屜可能有一個帶有行動呼籲的頁尾。其他的可能根本沒有頁尾。

與其在單個模態或抽屜元件中用條件props (如hasHeadershowFooter)定義每個佈局,不如將單個元件分解成多個可組合的子元件。

<Modal>
  <Modal.CloseButton />
  <Modal.Header> ... </Modal.Header>
  <Modal.Main> ... <Modal.Main>
</Modal>
<Drawer>
  <Drawer.Main> ... </Drawer.Main>
  <Drawer.Footer> ... </Drawer.Footer>
</Drawer>

透過使用元件組合,每個單獨的元件可以像它想的那樣自私,只在需要的時候和地方使用。這樣可以保持根元件的API乾淨,並且可以將許多 prop 轉移到它們特定的子元件上。

當回顧我們的Button元件的演變時,也許自私的設計的關鍵是有意義的。然而,讓我們再把它們應用到另一個普遍存在問題的元件--模態。

image.png

image.png

image.png

對於這個例子,我們在三個不同的模態佈局中得到了預見性的好處。這將有助於引導我們Modal的方向,同時沿途應用自私設計的每個關鍵。

首先,讓我們回顧一下我們的心理模型,並分解每個設計的佈局。

在 "Edit Profile"模式中,有定義的頁首、主頁和頁尾部分。也有一個關閉按鈕。在Upload Successful 中,有一個修改過的頁首,沒有關閉按鈕和一個類似英雄的影像。頁尾的按鈕也被拉長了。最後,在 Friends 模態中,關閉按鈕返回,但現在內容區可以滾動,而且沒有頁尾。

那麼,我們學到了什麼?

我們瞭解到,頁首、主頁和頁尾部分是可以互換的。它們可能存在於任何給定的檢視中,也可能不存在。我們還了解到,關閉按鈕的功能是獨立的,不與任何特定的佈局或部分相聯絡。

因為我們的Modal可以由可互換的佈局和安排組成,這就是我們採取可組合的子元件方法的標誌。這將使我們能夠根據需要在模態中插入和播放部件。

這種方法允許我們非常狹隘地定義我們的根Modal元件的職責。

有條件地以任何內容佈局的組合進行渲染。

這就是了。只要我們的Modal只是一個有條件渲染的容器,它就永遠不需要關心或對其內容負責。

隨著我們的模態的核心職責被定義,以及可組合的子元件方法被決定,讓我們來分解每個可組合的部分和它的作用。

組成部分角色
<Modal>這是整個 Modal 元件的入口點。這個容器負責何時何地渲染,模態的外觀,以及它所做的事情,比如處理可訪問性的考慮。
<Modal.CloseButton />一個可互換的 Modal 子元件,只有在需要的時候才可以包含。這個元件的工作方式類似於我們重構的 Button 元件。它將負責它的外觀,顯示的位置,以及它的作用。
<Modal.Header>標題部分將是本地HTML標題元素的一個抽象。它只不過是一個語義容器,用於顯示任何內容,如標題或圖片。
<Modal.Main>主部分將是本地HTML主元素的一個抽象。它只不過是任何內容的一個語義容器而已。
<Modal.Footer>頁尾部分將是本地HTML頁尾元素的一個抽象化。它只不過是任何內容的一個語義容器而已。

有了每個元件及其角色的定義,我們可以開始建立道具來支援這些角色和責任。

Modal

我們定義了Modal的基本職責,即知道何時有條件地渲染。這可以透過isShown這樣的 prop 來實現。因此,我們可以使用這些 prop ,只要它是 true`,Modal和它的內容就會渲染。

type ModalProps = {
  isShown: boolean;
}
<Modal isShown={showModal}>
  ...
</Modal>

任何造型和定位都可以直接用CSS在Modal元件中完成。目前不需要建立特定的 prop。

Modal.CloseButton

鑑於我們之前重構的Button元件,我們知道CloseButton應該如何工作。我們甚至可以用我們的Button來構建我們的CloseButton元件。

import { Button, ButtonProps } from 'components/Button';

export function CloseButton({ onClick, ...props }: ButtonProps) {
  return (
    <Button {...props} onClick={onClick} variant="ghost" theme="primary" />
  )
}
<Modal>
  <Modal.CloseButton onClick={closeModal} />
</Modal>

Modal.Header, Modal.Main, Modal.Footer

每個單獨的佈區域性分,Modal.HeaderModal.MainModal.Footer,都可以從它們的HTML等價物,即headermainfooter中獲取方向。這些元素中的每一個都支援子內容的任何變化,因此,我們的元件也會這樣做。

不需要特殊的 prop。它們只是作為語義容器。

<Modal>
  <Modal.CloseButton onClick={closeModal} />
  <Modal.Header> ... </Modal.Header>
  <Modal.Main> ... </Modal.Main>
  <Modal.Footer> ... </Modal.Footer>
</Modal>

有了我們的 Modal元件和它的子元件的定義,讓我們看看它們是如何被互換使用來建立這三種設計的。

注意:完整的標記和樣式沒有顯示出來,以便不影響核心的收穫。

EDIT PROFILE MODAL

在Edit Profile模態中,我們使用了每個Modal元件。然而,每一個都只是作為一個容器,它的樣式和位置都是自己的。這就是為什麼我們沒有為它們包含一個className prop。任何內容的樣式都應該由內容本身來處理,而不是我們的容器元件。

<Modal>
  <Modal.CloseButton onClick={closeModal} />

  <Modal.Header>
    <h1>Edit Profile</h1>
  </Modal.Header>

  <Modal.Main>
    <div className="modal-avatar-selection-wrapper"> ... </div>
    <form className="modal-profile-form"> ... </form>
  </Modal.Main>

  <Modal.Footer>
    <div className="modal-button-wrapper">
      <Button onClick={closeModal} theme="tertiary">Cancel</Button>
      <Button onClick={saveProfile} theme="secondary">Save</Button>
    </div>
  </Modal.Footer>
</Modal>

UPLOAD SUCCESSFUL MODAL

像前面的例子一樣,Upload Successful模態使用其元件作為無意見的容器。內容的樣式是由內容本身處理的。也許這意味著按鈕可以被modal-button-wrapper類拉伸,或者我們可以給Button元件新增一個"我看起來怎麼樣?"的道具,比如isFullWidth,以獲得更寬或全寬的尺寸。

<Modal>
  <Modal.Header>
    <img src="..." alt="..." />
    <h1>Upload Successful</h1>
  </Modal.Header>

  <Modal.Main>
    <p> ... </p>
    <div className="modal-copy-upload-link-wrapper"> ... </div>
  </Modal.Main>

  <Modal.Footer>
    <div className="modal-button-wrapper">
      <Button onClick={closeModal} theme="tertiary">Skip</Button>
      <Button onClick={saveProfile} theme="secondary">Save</Button>
    </div>
  </Modal.Footer>
</Modal>

FRIENDS MODAL

最後,我們的Friendsmodal取消了Modal.Footer部分。在這裡,在Modal.Main上定義溢位樣式可能很誘人,但這是將容器的責任擴充套件到它的內容。相反,處理這些樣式在modal-friends-wrapper類中更合適。

<Modal>
  <Modal.CloseButton onClick={closeModal} />

  <Modal.Header>
    <h1>AngusMcSix's Friends</h1>
  </Modal.Header>

  <Modal.Main>
      <div className="modal-friends-wrapper">
        <div className="modal-friends-friend-wrapper"> ... </div>
        <div className="modal-friends-friend-wrapper"> ... </div>
        <div className="modal-friends-friend-wrapper"> ... </div>
      </div>
  </Modal.Main>
</Modal>

總結

本文對元件設計中的一個重要概念——自私性進行了探討。自私性(Selfishness)在元件設計中是一種思維方式,意味著每個元件只關心其自身的功能和樣式,而不關心其他元件。該文章認為,自私性可以幫助開發者建立更高效、易於維護的元件。

文章闡述了以下四個實踐自私性的方法:

單一職責原則:元件應該有一個明確的功能,並僅關注該功能。這使元件更容易理解、測試和複用。

避免外部依賴:元件應該減少對外部資源的依賴,這有助於提高元件的獨立性和複用性。

封裝樣式:元件的樣式應該內部定義,避免受到外部樣式影響。這樣做可以確保元件在不同的環境中保持一致性。

明確介面:元件應該具有清晰、明確的介面,以便其他開發者能夠容易地瞭解和使用元件。

作者強調,自私性並不意味著開發者應該孤立地工作,而是鼓勵他們關注元件本身,從而提高元件的質量。透過遵循上述原則,開發者可以建立更加健壯、可維護和可擴充套件的元件,為整個專案帶來長遠的好處。

程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

原文:https://www.smashingmagazine.com/2023/01/key-good-component-d...

交流

有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章