精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

如何寫出更優雅的 React 組件 - 代碼結構篇

開發 前端
我們從代碼結構的角度來談談如何設計一個更優雅的 React 組件。優秀的組件有著一個清晰的目錄結構。這里的目錄結構分為項目級結構、單組件級結構。

[[438981]]

在日常團隊開發中大家寫的組件質量參差不齊,風格千差萬別。會因為很多需求導致組件無法擴展,或難以維護。導致很多業務組件的功能重復,使用起來相當難受。我們從代碼結構的角度來談談如何設計一個更優雅的 React 組件。

組件目錄結構

優秀的組件有著一個清晰的目錄結構。這里的目錄結構分為項目級結構、單組件級結構。

容器組件/展示組件

在項目中我們的目錄結構可以根據組件和業務耦合來劃分,和業務的耦合程度越低, 可復用性越強。展示組件只關注展示層, 可以在多個地方被復用, 它不耦合業務。容器組件主要關注業務處理,容器組件通過組合展示組件來構建完整視圖。

示例:

  1. src/ 
  2.   components/ (通用組件,與業務無關,可被其他所有組件調用) 
  3.     Button/ 
  4.       index.tsx 
  5.   containers/ (容器組件,與業務深度耦合,可被頁面組件調用) 
  6.     Hello/ 
  7.       Kitty/ (容器組件中的特有組件,不能與其他容器組件共享) 
  8.       index.tsx 
  9.     World/ 
  10.       components/ 
  11.       index.tsx 
  12.   hooks/ (公共的 hooks) 
  13.   pages/ (頁面組件,特定的頁面,無復用性) 
  14.     my-app/ 
  15.   store/ (狀態管理) 
  16.   services/ (接口定義) 
  17.   utils/ (工具類) 

組件目錄結構

我們可以根據文件類型/功能/職責等劃分不同的目錄。

  1. 根據文件類型可以分出 images 等目錄
  2. 根據文件功能可以分出 __tests__ 、demo 等目錄
  3. 根據文件職責可以分出 types 、utils 、hooks 等目錄
  4. 根據組件的特點可以用目錄劃分歸類
  1. HelloWorld/ (普通的業務組件) 
  2.   __tests__/ (測試用例) 
  3.   demo/ (組件示例) 
  4.   Bar/ (特有組件分類) 
  5.     Kitty.tsx (特有組件) 
  6.     Kitty.module.less 
  7.   Foo/ 
  8.   hooks/ (自定義 hooks) 
  9.   images/ (圖片目錄) 
  10.   types/ (類型定義) 
  11.   utils/ (工具類方法) 
  12.   index.tsx (出口文件) 

比如我最近寫的一個表格組件的目錄結構:

  1. ├─SheetTable 
  2. │  ├─Cell 
  3. │  ├─Header 
  4. │  ├─Layer 
  5. │  ├─Main 
  6. │  ├─Row 
  7. │  ├─Store 
  8. │  ├─types 
  9. │  └─utils 

組件內部結構

組件內部需要保持良好的順序邏輯,統一團隊規范。約定俗成后,這樣一目了然定義可以讓我們更清晰地去 Review。

導入順序

導入順序為 node_modules -> @/ 開頭文件 -> 相對路徑文件 -> 當前組件樣式文件

  1. // 導入 node_modules 依賴 
  2. import React from'react'
  3. // 導入公共組件 
  4. import Button from'@/components/Button'
  5. // 導入相對路徑組件 
  6. import Foo from'./Foo'
  7. // 導入對應同名的 .less 文件,命名為 styles 
  8. import styles from'./Kitty.module.less'

使用 組件名 + Props 形式命名 Props 類型并導出。

類型與參數書寫的順序保持一致,一般以 [a-z] 的順序定義。變量的注釋禁止放末尾,原因是會導致編輯器識別錯位,無法正確提示

  1. /** 
  2.  * 類型定義(命名:組件名 + Props) 
  3.  */ 
  4. export interface KittyProps { 
  5.   /** 
  6.    * 多行注釋(建議) 
  7.    */ 
  8.   email: string; 
  9.   // 單行注釋(不推薦) 
  10.   mobile: string; 
  11.   username: string; // 末尾注釋(禁止) 

使用 React.FC 定義

  1. const Kitty: React.FC<KittyProps> = ({ email, mobile, usename }) => {}; 

泛型,代碼提示更智能

以下例子,可以用過泛型讓 value 和 onChange 回調中的類型保持一致,并做到編輯器智能類型提示。

注意:泛型組件無法使用 React.FC 類型

  1. export interface FooProps<Value> { 
  2.   value: Value; 
  3.   onChange: (value: Value) =>void; 
  4.  
  5. exportfunction Foo<Value extends React.Key>(props: FooProps<Value>) {} 

禁止直接使用 any 類型

無論隱式和顯式的方式,都不推薦使用 any 類型。定義了 any 的參數會讓使用該組件的人產生極度困惑,無法明確地知道其中的類型。我們可以通過泛型的方式去聲明。

  1. // 隱式 any (禁止) 
  2. let foo; 
  3. function bar(param) {} 
  4.  
  5. // 顯式 any (禁止) 
  6. let hello: any
  7. function world(param: any) {} 
  8.  
  9. // 使用泛型繼承,縮小類型范圍 (推薦) 
  10. function Tom<P extends Record<string, any>>(param: P) {} 

一個組件對應一個樣式文件

我們以組件的顆粒度大小為抽象單元,樣式文件則應與組件本身保持一致。不推薦交叉引入樣式文件的做法,這樣會導致重構混亂,無法明確當前這個樣式被多少個組件使用。

  1. - Tom.tsx 
  2. - Tom.module.less 
  3. - Kitty.tsx 
  4. - Kitty.module.less 

內聯樣式

避免偷懶,要時刻保持優雅,隨手一個 style={} 是極為不推薦的。這樣不僅每次渲染都有重新創建的消耗,而且是清晰的 JSX 上的噪點,影響閱讀。

組件行數限制

組件需要明確的注釋,并保持 300 行以內的代碼行數。代碼行數可以通過配置 eslint 來做到限制(可以跳過注釋/空行的的統計):

  1. 'max-lines-per-function': [2, { max: 320, skipComments: true, skipBlankLines: true }], 

組件內部編寫代碼的順序

組件內部的順序為 state -> custom Hooks -> effects -> 內部 function -> 其他邏輯 -> JSX

  1. /** 
  2.  * 組件注釋(簡明概要) 
  3.  */ 
  4. const Kitty: React.FC<KittyProps> = ({ email }) => { 
  5.   // 1. state 
  6.  
  7.   // 2. custom Hooks 
  8.  
  9.   // 3. effects 
  10.  
  11.   // 4. 內部 function 
  12.  
  13.   // 5. 其他邏輯... 
  14.  
  15.   return ( 
  16.     <div className={styles.wrapper}> 
  17.       {email} 
  18.       <Child /> 
  19.     </div> 
  20.   ); 
  21. }; 

事件函數命名區分

內部方法按照 handle{Type}{Event} 命名,例如 handleNameChange。暴露外部的方法按照 on{Type}{Event},例如 onNameChange。這樣做的好處可以直接通過函數名區分是否為外部參數。

例如 antd/Button 組件片段:

  1. const handleClick = (e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement, MouseEvent>) => { 
  2.   const { onClick, disabled } = props; 
  3.   if (innerLoading || disabled) { 
  4.     e.preventDefault(); 
  5.     return
  6.   } 
  7.   (onClick as React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>)?.(e); 
  8. }; 

繼承原生元素 props 定義

原生元素 props 都繼承了 React.HTMLAttributes。某些特殊元素也會擴展自己的屬性,例如 InputHTMLAttributes。

我們定義一個自定義組件則可以通過繼承 React.InputHTMLAttributes ,讓其類型具有所有 input 的特性。

  1. export interface KittyProps extends React.InputHTMLAttributes<HTMLInputElement> { 
  2.   /** 
  3.    * 新增支持回車鍵事件 
  4.    */ 
  5.   onPressEnter?: React.KeyboardEventHandler<HTMLInputElement>; 
  6.  
  7. function Kitty({ onPressEnter, onKeyUp, ...restProps }: KittyProps) { 
  8.   function handleKeyUp(e: React.KeyboardEvent<HTMLInputElement>) { 
  9.     if (e.code.includes('Enter') && onPressEnter) { 
  10.       onPressEnter(e); 
  11.     } 
  12.     if (onKeyUp) { 
  13.       onKeyUp(e); 
  14.     } 
  15.   } 
  16.  
  17.   return<input onKeyUp={handleKeyUp} {...restProps} />; 

避免循環依賴

如果你寫的組件包含了循環依賴, 這時候你需要考慮拆分和設計模塊文件

  1. // --- Foo.tsx --- 
  2. import Bar from'./Bar'
  3.  
  4. export interface FooProps {} 
  5.  
  6. exportconst Foo: React.FC<FooProps> = () => {}; 
  7. Foo.Bar = Bar; 
  8.  
  9. // --- Bar.tsx ---- 
  10. import { FooProps } from'./Foo'

上面 Foo 和 Bar 組件就形成了一個簡單循環依賴, 盡管它不會造成什么運行時問題. 解決方案就是將 FooProps 抽取到單獨的文件:

  1. // --- types.ts --- 
  2. export interface FooProps {} 
  3.  
  4. // --- Foo.tsx --- 
  5. import Bar from'./Bar'
  6. import { FooProps } from'./types'
  7.  
  8. exportconst Foo: React.FC<FooProps> = () => {}; 
  9. Foo.Bar = Bar; 
  10.  
  11. // --- Bar.tsx ---- 
  12. import { FooProps } from'./types'

相對路徑不要超過兩級

當項目復雜的情況下,目錄結構會越來越深,文件會有很長的 ../ 路徑,這樣看起來很不優雅:

  1. import { ButtonProps } from'../../../components/Button'

我們可以通過在 tsconfig.json 中配置

  1. "paths": { 
  2.   "@/*": ["src/*"

和 vite 中配置

  1. alias: { 
  2.   '@/': `${path.resolve(process.cwd(), 'src')}/`, 

現在我們可以導入相對于 src 的模塊:

  1. import { ButtonProps } from'@/components/Button'

當然更徹底一點,可以使用 monorepo 的項目管理方式來解耦各個組件。只要搭建一套腳手架,就能管理(構建、測試、發布)多個 package

不要直接使用 export default 導出未命名的組件

這種方式導出的組件在 React Inspector 查看時會顯示為 Unknown

  1. // 錯誤做法 
  2. exportdefault () => {}; 
  3.  
  4. // 正確做法 
  5. exportdefaultfunction Kitty() {} 
  6.  
  7. // 正確做法:先聲明后導出 
  8. function Kitty() {} 
  9.  
  10. exportdefault Kitty; 

結語

以上是寫 React 組件在目錄結構以及編碼規則上需要注意的點,后續我們講解如何在思維上保持優雅。

 

責任編輯:姜華 來源: 前端星辰
相關推薦

2021-12-13 14:37:37

React組件前端

2022-03-11 12:14:43

CSS代碼前端

2022-05-13 08:48:50

React組件TypeScrip

2023-12-21 10:26:30

??Prettier

2016-11-25 13:50:15

React組件SFC

2021-01-04 07:57:07

C++工具代碼

2019-09-20 15:47:24

代碼JavaScript副作用

2017-09-01 14:18:50

前端React組件

2020-05-14 09:15:52

設計模式SOLID 原則JS

2018-07-12 14:20:33

SQLSQL查詢編寫

2020-07-15 08:17:16

代碼

2020-05-08 14:45:00

JS代碼變量

2022-08-09 13:22:26

Hooksreactvue

2020-05-11 15:23:58

CQRS代碼命令

2021-09-01 08:55:20

JavaScript代碼開發

2013-06-07 14:00:23

代碼維護

2021-11-30 10:20:24

JavaScript代碼前端

2022-02-17 10:05:21

CSS代碼前端

2022-02-08 19:33:13

技巧代碼格式

2020-05-19 15:00:26

Bug代碼語言
點贊
收藏

51CTO技術棧公眾號

精品国产乱码久久久久久虫虫漫画| 国精产品一区一区三区mba视频 | 一区二区三区亚洲| 污视频网站观看| bt在线麻豆视频| 成人动漫精品一区二区| 国产精品69久久| 欧美片一区二区| 国产剧情在线观看一区| 日韩免费一区二区| 少妇性l交大片| 中国av在线播放| 久久嫩草精品久久久精品一| 成人在线免费观看视视频| 国产精品30p| 我不卡手机影院| 亚洲精选中文字幕| 中文字幕无码毛片免费看| 在线国产成人影院| 亚洲h精品动漫在线观看| 亚洲欧洲三级| 天堂在线中文网| 韩国av一区二区三区在线观看 | 黄色精品视频| 亚洲电影在线免费观看| 在线视频一区观看| 日韩av视屏| www.亚洲人| av电影成人| 一级片一区二区三区| 久久成人免费| 国模精品视频一区二区| 老熟妻内射精品一区| 日韩免费久久| 亚洲色图狂野欧美| 伦理片一区二区| 久久久91麻豆精品国产一区| 日本韩国欧美一区| 欧美日韩中文在线视频| ririsao久久精品一区| 亚洲欧美区自拍先锋| 亚洲免费视频一区| 精品无人乱码| 久久久久久久网| 精品欧美日韩在线| 日本黄色三级视频| 成人激情午夜影院| 波多野结衣一区二区三区在线观看| 一级黄色大片免费| 免费成人av资源网| 国产精品一区专区欧美日韩| 日本中文字幕在线观看视频| 免费在线成人| 奇米四色中文综合久久| 国产精品视频免费播放| 亚洲免费中文| 日韩美女免费观看| 极品国产91在线网站| 国产精品亚洲产品| 国产成人亚洲综合91| 中文字幕在线观看视频免费| 日韩精品亚洲一区二区三区免费| 国产v综合ⅴ日韩v欧美大片 | 国产伦精品一区二区三区免费视频| 国产三级三级在线观看| 国产美女精品人人做人人爽 | 亚洲国产精品毛片av不卡在线| 性欧美18~19sex高清播放| 精品人伦一区二区三区蜜桃网站| 国产免费观看高清视频| 最新欧美色图| 欧美日韩在线一区二区| 五月天视频在线观看| 日韩精品一级| 日韩精品欧美国产精品忘忧草 | 国产精品国模大尺度视频| 宅男一区二区三区| 日韩成人伦理| 精品久久久久久中文字幕| 女性隐私黄www网站视频| 精品视频一区二区三区四区五区| 欧美日韩精品欧美日韩精品| 亚洲一级片免费观看| 中文字幕一区二区三区日韩精品| 日韩av在线网站| 欧美三级视频网站| 久久久久久久久丰满| 国模叶桐国产精品一区| 日韩黄色一级视频| 丰满放荡岳乱妇91ww| 青青草成人网| 手机在线免费看av| 欧美午夜激情视频| 日本高清免费在线视频| 欧美一性一交| 日韩视频永久免费观看| 国产黄色片视频| 免费在线观看精品| 国产精品久久久久久久久久直播| 欧美精品a∨在线观看不卡| 亚洲欧美一区二区三区国产精品| 三上悠亚久久精品| 国产精品天堂蜜av在线播放| 亚洲第一精品久久忘忧草社区| 蜜桃精品一区二区| 中文字幕一区二区三区欧美日韩| 91禁国产网站| 国产毛片毛片毛片毛片| 久久精品一二三| 日本成人在线不卡| 国产精品伦一区二区| 日韩极品精品视频免费观看| 91麻豆精品成人一区二区| 国产精品永久| 成人在线免费网站| 日本电影在线观看网站| 欧美性69xxxx肥| 中文字幕18页| 亚洲国产精品日韩专区av有中文 | 粉嫩蜜臀av国产精品网站| 日韩资源av在线| 久久青草伊人| 精品国产一区二区三区av性色 | 久久精品无码一区二区三区毛片| 免费黄色成人| 国模gogo一区二区大胆私拍 | 日韩精品999| 青青青在线视频| 久色婷婷小香蕉久久| 麻豆蜜桃91| 高潮在线视频| 精品国产乱码久久久久久老虎| 99热99这里只有精品| 石原莉奈在线亚洲三区| 久久av二区| 国产拍在线视频| 欧美xxx久久| 久久国产一级片| 国产一区视频导航| 自拍偷拍一区二区三区| 国语自产精品视频在线看抢先版结局| 亚洲女人天堂成人av在线| 日本一本高清视频| 成人精品小蝌蚪| www.男人天堂网| 高清日韩欧美| 国自在线精品视频| 人妻偷人精品一区二区三区| 亚洲6080在线| 久久久久久久久免费看无码 | 国内精品小视频在线观看| 国产高清视频免费| 一个色综合av| 人妻激情偷乱频一区二区三区 | 一区二区成人网| 精品香蕉视频| 国产精品视频中文字幕91| 999在线视频| 欧美日韩一区高清| 国产又色又爽又高潮免费| 久久成人免费网| 青青在线免费视频| 在线日韩成人| 2018日韩中文字幕| 国产一级片在线| 在线免费一区三区| 99久久99久久精品免费| 极品美女销魂一区二区三区 | 制服丝袜中文字幕亚洲| 国产av无码专区亚洲av毛网站| 高清在线不卡av| 欧美日韩亚洲一| av资源久久| 亚洲一区二区少妇| 福利影院在线看| 尤物tv国产一区| 99久久免费国产精精品| 亚洲一二三区不卡| 国产黄片一区二区三区| 久久国产人妖系列| 精品少妇人欧美激情在线观看| 亚洲欧洲免费| 成人观看高清在线观看免费| 青草在线视频| 亚洲日韩中文字幕在线播放| 国产裸体无遮挡| 疯狂做受xxxx高潮欧美日本| 亚洲精品视频网址| 高清av一区二区| 久久精品视频91| 国产综合亚洲精品一区二| 欧美国产一区二区在线| 精品视频一二| 国产成人+综合亚洲+天堂| 成人福利片网站| 国产丝袜精品视频| 国产同性人妖ts口直男| 日韩欧美在线看| 欧美成人一区二区三区高清| 久久久精品天堂| zjzjzjzjzj亚洲女人| 欧美a级一区二区| 中文字幕无码精品亚洲资源网久久| 国产在线观看91一区二区三区 | 久久久亚洲成人| 又爽又大又黄a级毛片在线视频| 亚洲精品一区二区三区精华液 | 免费在线成人网| 日韩不卡视频一区二区| 欧美精品色图| 精品一区二区三区国产| 久久亚洲精精品中文字幕| 国产精品99久久久久久www | 国产女人精品视频| 麻豆蜜桃在线观看| 色噜噜狠狠色综合网图区| 四虎精品成人免费网站| 日韩三级av在线播放| 怡春院在线视频| 一本一道综合狠狠老| 国产在线视频第一页| 中文字幕中文字幕在线一区 | 亚洲视频在线观看三级| 亚洲国产日韩一区无码精品久久久| 成人av网在线| 亚洲 自拍 另类 欧美 丝袜| 免费欧美日韩国产三级电影| 99re在线视频免费观看| 亚洲精品日韩久久| 国产视频在线观看网站| 亚洲综合色网| 日本特级黄色大片| 久久婷婷蜜乳一本欲蜜臀| 欧美日韩亚洲一区二区三区在线观看 | 免费一级毛片在线观看| 亚洲精品成人久久| 色婷婷中文字幕| 亚洲国产成人91精品| 国产免费福利视频| 宅男噜噜噜66一区二区66| 国产一区二区小视频| 欧美视频一二三区| 中文字幕视频免费观看| 在线免费观看视频一区| 中国老头性行为xxxx| 在线免费视频一区二区| 中文字幕码精品视频网站| 欧美性大战久久久久久久| 波多野结衣网站| 在线观看网站黄不卡| 懂色av中文字幕| 在线免费视频一区二区| 在线观看一二三区| 7777精品伊人久久久大香线蕉完整版| 91成人国产综合久久精品| 制服丝袜亚洲精品中文字幕| 国产伦精品一区二区三区四区 | 在线看免费毛片| 经典一区二区三区| 99久久综合网| av影院午夜一区| 国产中年熟女高潮大集合| 国产欧美精品一区aⅴ影院| 精品一区二区在线观看视频| 亚洲视频一区二区在线观看| 国产性一乱一性一伧一色| 午夜天堂影视香蕉久久| 婷婷激情五月网| 欧美影院一区二区三区| 国产伦精品一区二区三区免.费| 精品日韩一区二区三区免费视频| 色婷婷av一区二区三区之红樱桃| 亚洲免费小视频| 婷婷免费在线视频| 欧美激情精品久久久久久免费印度 | 91精品视频免费在线观看| 欧美一区二区在线看| 亚洲精品久久久久久久久久 | 一区二区三区四区免费| 国产精品欧美精品| 丝袜 亚洲 另类 欧美 重口| 婷婷中文字幕一区三区| 中文字幕久久久久| 精品99999| av大片在线播放| 欧美激情久久久久| 999国产精品亚洲77777| www.久久艹| 精品视频免费| 久久这里只有精品18| 爽好久久久欧美精品| 亚洲国产综合av| 久久久精品国产99久久精品芒果 | 真实乱偷全部视频| 久久精品亚洲精品国产欧美| 中文字幕电影av| 在线视频综合导航| 亚洲经典一区二区| 日韩在线视频导航| 波多野结衣亚洲| 97久久人人超碰caoprom欧美 | 五月天色婷婷综合| 亚洲在线网站| 熟妇女人妻丰满少妇中文字幕| 久久久99精品久久| 久草免费在线观看视频| 91成人免费电影| 人妻少妇一区二区三区| 久久天天躁狠狠躁夜夜躁| 天堂8中文在线最新版在线| 亚洲xxxx视频| 水蜜桃精品av一区二区| 日韩国产欧美亚洲| 国产成人综合在线| 永久免费看片视频教学| 色综合久久88色综合天天免费| 午夜精品久久久久久久96蜜桃| 中文字幕在线观看日韩| 免费成人美女女| 精品国产免费久久久久久尖叫| 欧美另类综合| 午夜剧场在线免费观看| 亚洲国产高清aⅴ视频| 欧美激情亚洲综合| 亚洲激情视频在线| 男女免费观看在线爽爽爽视频| 91亚洲人电影| 日韩欧美一区二区三区在线视频 | 黄频视频在线观看| 日韩电影免费一区| 人妻精品久久久久中文字幕| 亚洲高清一区二区三区| 国产av一区二区三区精品| 爱福利视频一区| 国产精品va视频| 在线免费观看成人网| 美女一区二区三区| jizzjizzjizz国产| 欧美日韩综合在线| 自拍视频在线网| 国产精品免费在线免费| 精品亚洲成人| 手机在线看福利| 国产精品三级av在线播放| 亚洲精品无码久久久久| 伊人av综合网| 欧美a视频在线| 一级二级三级欧美| 久久99久久久久久久久久久| 久久久久99精品成人| 7799精品视频| 日日夜夜天天综合入口| 国产日韩精品推荐| 国产毛片一区| 国产精品美女高潮无套| 欧美日韩中文国产| 成人高清免费在线| 国产精品jizz视频| 亚洲在线观看| 综合 欧美 亚洲日本| 欧美久久婷婷综合色| 97超碰在线公开在线看免费| 国产日韩欧美二区| 三级欧美韩日大片在线看| 高清国产在线观看| 91精品国产色综合久久久蜜香臀| 五月天激情在线| 久久99欧美| 麻豆国产91在线播放| 老女人性淫交视频| 日韩av在线网| 久久av日韩| 中文字幕日韩精品无码内射| 91免费看视频| 一区二区久久精品66国产精品 | 99久久久国产精品免费调教网站| 一区二区三区av| 丰满亚洲少妇av| 小泽玛利亚一区二区三区视频| 久久99精品国产99久久6尤物| 黄色成人美女网站| www.这里只有精品| 亚洲第一福利视频在线| 国产黄色免费在线观看| 91一区二区三区| 久久国产88| 黑人巨大精品一区二区在线| 精品亚洲一区二区三区四区五区| 91福利精品在线观看| 免费看欧美黑人毛片| 久久九九影视网| www.成人免费视频| 国产精品久久久久久av下载红粉| 欧美日韩精品| 91精品国自产在线| 亚洲第一网站男人都懂| 97成人超碰| 日本wwww视频| 亚洲欧美日本韩国| 成年人在线观看|