<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一種更好的前端組件結(jié)構(gòu):組件樹

          共 22772字,需瀏覽 46分鐘

           ·

          2024-06-18 08:48


              

          大廠技術(shù)  高級前端  Node進(jìn)階

          點(diǎn)擊上方 程序員成長指北,關(guān)注公眾號

          回復(fù)1,加入高級Node交流群

          一種清晰簡潔的方式來查看前端項目中的前端組件(來源:Midjourney)

          自很久以前遵循互聯(lián)網(wǎng)上的建議以來,我一直采用了某種“能工作就行”的組件結(jié)構(gòu)。

          場景

          讓我們首先想象一個簡化的前端應(yīng)用程序目錄結(jié)構(gòu),如下所示:

          public/
            some-image.jpg
          pages/
            index.tsx

          components/
            Heading.tsx
            Logo.tsx
            Layout.tsx
            BoxContainer.tsx
            Footer.tsx

          問題所在

          上面的簡單應(yīng)用程序結(jié)構(gòu)很難解釋這些組件之間是如何相互作用的。

          例如,您可能會猜測Layout.tsx導(dǎo)入Footer.tsxHeader.tsx,而這又可能導(dǎo)入BoxContainer.tsx。但這僅僅從文件結(jié)構(gòu)上是不清楚的。

          更糟糕的是,隨著應(yīng)用程序的增長,組件列表將變得越來越難以推斷它們是如何依賴的。

          簡單方法:扁平組件結(jié)構(gòu)

          通常首先想到的是將組件組織到語義正確的目錄中。

          下面是這種方法的典型結(jié)果:

          public/
            some-image.jpg
          pages/
            index.tsx

          components/
            layout/
              Layout.tsx
              Heading.tsx
              Footer.tsx
            common/
              Heading.tsx
              BoxContainer.tsx

          問題#1:很難擴(kuò)展好名字

          作為一個開發(fā)人員,您會嘗試為每個目錄創(chuàng)建好的名稱和分類,如containersheadings等。

          問題是您需要為目錄考慮更多的分類,而不僅僅是組件名稱。

          你經(jīng)常會忍不住說,“我就把這個移到公共目錄吧?!睋碛衏ommon目錄是你所追求的目標(biāo)相悖的反模式,但是在這種結(jié)構(gòu)下,很容易被吸引進(jìn)入其中。

          而且當(dāng)應(yīng)用程序變得足夠大時,您可能不得不開始考慮創(chuàng)建另一級目錄來保持內(nèi)容的組織性。

          這需要創(chuàng)建更多的名稱,增加了存儲庫用戶的認(rèn)知負(fù)荷。最終這種方法無法很好地擴(kuò)展。

          問題#2:目錄名稱的認(rèn)知負(fù)荷增加

          在此之前,那些瀏覽代碼庫的人首先會通過組件的名稱以及它們之間的關(guān)系來初步了解每個組件的功能。

          現(xiàn)在他們還需要理解你創(chuàng)建的目錄名稱,如果這些名稱在語義上不符合整體,這可能會使他們更加困惑。

          更好的方法:組件樹模式

          使用這種方法,您的重點(diǎn)是擁有命名良好的組件,這些組件隱式地解釋了它們的組成,而不用特意對具有不同名稱的組件組進(jìn)行分類。

          組件導(dǎo)入規(guī)則

          • 可以向上導(dǎo)入,除了它自己的父級
          • 可以導(dǎo)入同級
          • 無法導(dǎo)入同級組件
          • 無法導(dǎo)入其父級
          public/
            some-image.jpg
          pages/
            index.tsx

          components/
            Layout/
              components/
                Heading/
                  components/
                    Logo.tsx
                    Menu.tsx
                  Heading.tsx
                CopyrightIcon.tsx
                Footer.tsx
              Layout.tsx
            BoxContainer.tsx

          讓我們展示Footer.tsx的內(nèi)容,并使用上面列出的規(guī)則作為示例:

          // components/Layout/components/Footer.tsx

          // Can import upwards, except its own parent
          import { BoxContainer } from '../../BoxContainer.tsx';
          // Can import siblings
          import { CopyrightIcon } from './CopyrightIcon.tsx';

          // WRONG: Cannot import sibling's components
          // import { Menu } from './Heading/components/Menu.tsx';
          // WRONG: Cannot import its parent
          // import { Layout } from '../Layout.tsx';

          export const Footer = () => (
            <BoxContainer>
              <CopyrightIcon />
              <p>All rights reserved, etc.</p>
            </BoxContainer>

          )

          優(yōu)點(diǎn)#1:明顯的子組件關(guān)系

          組件樹模式消除了猜測;組件之間的關(guān)系立即變得清晰明了。例如,Menu.tsx 作為 Heading.tsx 的內(nèi)部依賴被整齊地嵌套在其中。

          同樣清晰的是Menu.tsx沒有被其他任何組件使用,這有助于您在日常開發(fā)任務(wù)中清理代碼時盡早忽略它。

          優(yōu)點(diǎn)2:可重用性的定義更加細(xì)致入微

          在簡單的方法中,組件被分為“常見”和“非常見”兩種??紤]到可重用性,組件樹有助于避免這種無效的二元思維。

          components/
            Layout/
              components/
                Heading/
                  components/
                  - Logo.tsx
                    Menu.tsx
                  Heading.tsx
              + Logo.tsx
                CopyrightIcon.tsx
                Footer.tsx
              Layout.tsx
            BoxContainer.tsx

          在上面的例子中,如果Logo.tsx對于更多的組件變得必要,而不僅僅是Menu.tsx,我們可以簡單地將其上移一級。對于BoxContainer.tsx來說,它可能沒有足夠的可重用性(或“通用性”),但在Layout.tsx組件的上下文中它是足夠可重用的。

          優(yōu)點(diǎn)#3:盡量減少命名

          由于您有組件樹,因此不需要將目錄名分類在組件名之上。組件名稱是分類,當(dāng)您看到組件由哪些內(nèi)部組件組成時,為組件確定好的名稱也會更容易。

          額外的好處:從組件中提取代碼到單獨(dú)的文件中,而無需考慮名稱

          現(xiàn)在我們考慮一種情況,您希望從Footer.tsx中提取一些實用程序函數(shù),因為文件變得有點(diǎn)大,并且您認(rèn)為可以從中分解一些邏輯,而不是分解更多的UI。

          雖然你可以創(chuàng)建一個utils/目錄,但這會迫使你選擇一個文件名來放置你的實用函數(shù)。

          相反,選擇使用文件后綴,如Footer.utils.tsxFooter.test.tsx。

          components/
            Layout/
              components/
                Heading/
                  components/
                    Logo.tsx
                    Menu.tsx
                  Heading.tsx
                CopyrightIcon.tsx
              + Footer.utils.tsx
                Footer.tsx
              Layout.tsx
            BoxContainer.tsx

          這樣你就不必去想一個很合適的名字,如emailFormatters.ts或非常模糊的東西,如helpers.ts。避免命名帶來的認(rèn)知負(fù)擔(dān),這些實用程序?qū)儆?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">Footer.tsx,可以由Footer.tsx及其內(nèi)部組件使用(再次向上導(dǎo)入)。

          組件樹的反駁觀點(diǎn)

          “太多的組件目錄了”

          第一次看到這個結(jié)構(gòu),這是大多數(shù)人的下意識反應(yīng)。

          是的,有很多“組件”目錄。但當(dāng)我與團(tuán)隊一起確定項目結(jié)構(gòu)時,我總是強(qiáng)調(diào)清晰度的重要性。

          我在一個代碼庫中衡量成功的方法之一是高級和初級開發(fā)人員對于清晰度的看法,而在這方面,我發(fā)現(xiàn)組件樹總是對實現(xiàn)這個目標(biāo)起到重要作用。

          “呃:import … from ./MyComponent/MyComponent.tsx?

          雖然import … from ./MyComponent/MyComponent.tsx可能看起來不漂亮,但它直接指示組件來自哪里帶來的清晰度更重要。

          關(guān)于導(dǎo)入字符串,以下是為開發(fā)人員增加認(rèn)知負(fù)荷的示例。

          • 使用像import ... from 'common/components'這樣的導(dǎo)入別名對開發(fā)人員來說是一種精神負(fù)擔(dān)
          • 到處都有index.ts文件,只需要寫import ... from './MyComponent'。但對于按文件搜索的開發(fā)人員來說,找到正確的文件可能需要更多的時間。

          最終比較:復(fù)雜場景

          多虧了像ChatGPT這樣的工具,為更復(fù)雜的場景測試這樣的模式非常容易。

          在解釋了結(jié)構(gòu)之后,我讓ChatGPT在左列生成“平面”目錄結(jié)構(gòu),在右邊生成我稱為“組件樹”的結(jié)構(gòu)。

          Flat Structure                      |  Component Trees
          ------------------------------------+---------------------------------------------------
          pages/                              |  pages/
            index.tsx                         |    index.tsx
            shop.tsx                          |    shop.tsx
            product/                          |    product/
              [slug].tsx                      |      [slug].tsx
            cart.tsx                          |    cart.tsx
            checkout.tsx                      |    checkout.tsx
            about.tsx                         |    about.tsx
            contact.tsx                       |    contact.tsx
            login.tsx                         |    login.tsx
            register.tsx                      |    register.tsx
            user/                             |    user/
              dashboard.tsx                   |      dashboard.tsx
              orders.tsx                      |      orders.tsx
              settings.tsx                    |      settings.tsx
                                              |  
          components/                         |  components/
            layout/                           |    Layout/
              Layout.tsx                      |      components/
              Header.tsx                      |        Header/
              Footer.tsx                      |          components/
              Sidebar.tsx                     |            Logo.tsx
              Breadcrumb.tsx                  |            NavigationMenu.tsx
            common/                           |            SearchBar.tsx
              Button.tsx                      |            UserIcon.tsx
              Input.tsx                       |            CartIcon.tsx
              Modal.tsx                       |          Header.tsx
              Spinner.tsx                     |        Footer/
              Alert.tsx                       |          components/
            product/                          |            SocialMediaIcons.tsx
              ProductCard.tsx                 |            CopyrightInfo.tsx
              ProductDetails.tsx              |          Footer.tsx
              ProductImage.tsx                |      Layout.tsx
              ProductTitle.tsx                |    BoxContainer.tsx
              ProductPrice.tsx                |    Button.tsx
              AddToCartButton.tsx             |    Input.tsx
            filters/                          |    Modal.tsx
              SearchFilter.tsx                |    Spinner.tsx
              SortFilter.tsx                  |    Alert.tsx
            cart/                             |    ProductCard/
              Cart.tsx                        |      components/
              CartItem.tsx                    |        ProductImage.tsx
              CartSummary.tsx                 |        ProductTitle.tsx
            checkout/                         |        ProductPrice.tsx
              CheckoutForm.tsx                |        AddToCartButton.tsx
              PaymentOptions.tsx              |      ProductCard.tsx
              OrderSummary.tsx                |    ProductDetails/
            user/                             |      components/
              UserProfile.tsx                 |        ProductSpecifications.tsx
              UserOrders.tsx                  |        ProductReviews.tsx
              LoginBox.tsx                    |        ProductReviewForm.tsx
              RegisterBox.tsx                 |      ProductDetails.tsx
            about/                            |    SearchFilter.tsx
              AboutContent.tsx                |    SortFilter.tsx
            contact/                          |    Cart/
              ContactForm.tsx                 |      components/
            review/                           |        CartItemList.tsx
              ProductReview.tsx               |        CartItem.tsx
              ProductReviewForm.tsx           |        CartSummary.tsx
            address/                          |      Cart.tsx
              ShippingAddress.tsx             |    CheckoutForm/
              BillingAddress.tsx              |      components/
            productInfo/                      |        PaymentDetails.tsx
              ProductSpecifications.tsx       |        BillingAddress.tsx
            cartInfo/                         |        ShippingAddress.tsx
              CartItemList.tsx                |      CheckoutForm.tsx
            userDetail/                       |    PaymentOptions.tsx
              UserSettings.tsx                |    OrderSummary.tsx
            icons/                            |    UserProfile/
              Logo.tsx                        |      components/
              SocialMediaIcons.tsx            |        UserOrders.tsx
              CartIcon.tsx                    |        UserSettings.tsx
              UserIcon.tsx                    |      UserProfile.tsx
                                              |    LoginBox.tsx
                                              |    RegisterBox.tsx
                                              |    AboutContent.tsx
                                              |    ContactForm.tsx

          這是一個沒有任何測試文件、實用程序文件或類似文件的示例。

          對于組件樹結(jié)構(gòu),您可以在組件目錄中添加后綴為的實用程序或測試文件。

          至于平面結(jié)構(gòu),你可能需要創(chuàng)建一個單獨(dú)的 utils 目錄來理解已經(jīng)相當(dāng)復(fù)雜的認(rèn)知負(fù)荷。

          最后

          有機(jī)會的話可以嘗試這個組件結(jié)構(gòu)。你會發(fā)現(xiàn)它是如此的直觀和高效,以至于不會再回到其他更復(fù)雜的結(jié)構(gòu),它們沒有簡化組件管理的能力。

          本文翻譯自 A Better Frontend Component Structure: Component Trees,作者:William Bernting, 略有刪改。 譯者:南城




          Node 社群

              


          我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。

             “分享、點(diǎn)贊在看” 支持一下

          瀏覽 284
          3點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          3點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  骚逼综合网| 久久久偷拍 | 国产精品鸡巴 | 91在线成人免费视频 | 黃色A片成人直播啪啪 |