精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

国产精品久久久久久久久久直播 | 精品无人区乱码1区2区3区在线| 欧美高清在线视频观看不卡| 污污免费在线观看| 天天操天天干天天舔| 成人久久电影| 日韩女优制服丝袜电影| 中文字幕99| 日韩中文字幕影院| 亚洲综合婷婷| 亚洲精品国产精品国产自| 国产裸体免费无遮挡| av网站在线看| 国产乱子伦一区二区三区国色天香| 中文字幕日韩电影| 亚洲乱码国产一区三区| 污污的网站在线看| 日本一区二区三区四区在线视频| 国产精品ⅴa在线观看h| 亚洲综合自拍网| 2020日本在线视频中文字幕| 久久精品水蜜桃av综合天堂| 99久久伊人精品影院| 亚洲无码精品一区二区三区| 美女久久99| 天天综合网 天天综合色| 一区二区精品在线| av中文字幕免费在线观看| 9191国语精品高清在线| 欧美色图一区二区三区| 欧洲精品一区二区三区久久| 精品孕妇一区二区三区| 精品亚洲aⅴ乱码一区二区三区| 正在播放国产一区| 一本色道久久综合亚洲精品图片| 日日夜夜天天综合| 亚洲h在线观看| 国产原创精品| 丰满人妻一区二区| 亚洲国内自拍| 欧美风情在线观看| 少妇精品无码一区二区三区| 日韩护士脚交太爽了| 国产精品美日韩| 在线播放国产一区中文字幕剧情欧美| 亚洲免费一级视频| 天天免费亚洲黑人免费| 午夜精品久久久久久久久| 青青视频免费在线| 亚洲AV午夜精品| 一本久道久久久| 久久久久久免费精品| 欧美黄片一区二区三区| 牛牛国产精品| 欧美日韩一区二区在线观看视频| 亚洲第一精品福利| 亚洲熟女乱综合一区二区| 日本久久一区| 欧美嫩在线观看| 丁香六月激情婷婷| 日本大胆在线观看| 一区二区三区不卡视频| 麻豆91蜜桃| a级片在线免费看| 国产美女视频91| 成人欧美一区二区三区黑人孕妇| 欧美黑吊大战白妞| 国产精品一区二区99| 亚洲女人天堂成人av在线| 欧美激情国内自拍| 日韩视频一区二区三区四区| 色香蕉成人二区免费| 91蝌蚪视频在线观看| 懂色aⅴ精品一区二区三区| 亚洲欧美区自拍先锋| 99热都是精品| 飘雪影院手机免费高清版在线观看| 蜜臀精品一区二区三区在线观看| 久久乐国产精品| 日韩成人av毛片| 久久精品三级| 成人午夜在线视频一区| 蜜桃久久一区二区三区| 久久亚洲精华国产精华液 | 日本学生初尝黑人巨免费视频| 青青一区二区三区| 久久国产精品久久久久| 91香蕉在线视频| 欧美三区视频| 亚洲性视频网站| 青青操在线视频观看| 国产精品豆花视频| 日本免费在线精品| 国产精品一级二级| 91在线观看高清| 在线码字幕一区| 99热99re6国产在线播放| 色偷偷88欧美精品久久久| www..com日韩| 日韩一区二区三区免费| 色综合久久天天综合网| 日本中文字幕影院| 久久中文字幕导航| 久久精彩免费视频| 国产又大又黄又粗| 成人在线综合网| 亚洲欧洲精品一区二区| 97人人在线视频| 538prom精品视频线放| 日本男人操女人| 视频国产精品| x99av成人免费| 国产成人无码av| 国产精品毛片| 91青青草免费观看| 97视频精彩视频在线观看| 亚洲一区二区免费视频| 一区二区三区 欧美| 日本成人中文| 欧美乱妇高清无乱码| 最新中文字幕免费| 久久精品一区八戒影视| 91免费黄视频| 欧美一区 二区 三区| 精品少妇一区二区三区免费观看 | 97久久久久久久| 国产福利电影一区二区三区| 亚洲欧美日韩精品综合在线观看| 欧美成人二区| 日韩欧美极品在线观看| 中文字幕乱妇无码av在线| 俺要去色综合狠狠| 国产91色在线|免| 天天干天天干天天干| 亚洲色图欧美在线| 国产一二三四在线视频| 国产精品黄网站| 国产一区二区av| 国产免费一级视频| 成人自拍视频在线| 青青在线免费视频| 巨大黑人极品videos精品| 亚洲精品福利视频| 久久久精品免费看| 青草国产精品久久久久久| 国产日韩欧美二区| 黄视频网站在线| 欧美日韩国产大片| 懂色av蜜桃av| 欧美成人一品| 91成人在线播放| 蜜桃av鲁一鲁一鲁一鲁俄罗斯的| 91小视频免费看| 你懂的网址一区二区三区| 激情影院在线| 欧美一区二区三区精品| 精品无码人妻少妇久久久久久| 国产精品色呦| 97色在线观看免费视频| 亚洲国产www| 亚洲精品欧美激情| 少妇欧美激情一区二区三区| 波多野结衣在线观看一区二区| 久久天天躁日日躁| 日日夜夜综合网| 99精品欧美一区| 老太脱裤子让老头玩xxxxx| 狠狠一区二区三区| 亚洲片在线观看| 日本三级一区二区三区| 欧美国产欧美亚州国产日韩mv天天看完整| 亚洲自拍小视频免费观看| 日本韩国在线观看| 国产精品日产欧美久久久久| 国产免费又粗又猛又爽| 久久在线播放| 俄罗斯精品一区二区| 黄页在线观看免费| 日韩高清a**址| 中文字幕在线观看视频网站| 久久新电视剧免费观看| 中文字幕在线观看一区二区三区| 亚洲成人不卡| 一区二区三区视频免费在线观看| 国产精品自拍视频一区| 蜜臀a∨国产成人精品| 亚洲一区二区在线观| 成人美女视频| 国产一区二区三区在线观看视频| 中文人妻av久久人妻18| 欧美激情一区二区三区不卡| 日本国产一级片| 黑人一区二区三区四区五区| 久久精品aaaaaa毛片| 欧美人与性动交xxⅹxx| 久久精品视频导航| 韩国av在线免费观看| 日韩欧美视频一区二区三区| 69xxx免费| 日本欧美一区二区三区| 免费看日b视频| 色婷婷av一区二区三区丝袜美腿| 三级精品视频久久久久| 久久午夜无码鲁丝片| 国产在线一区观看| 2019日韩中文字幕mv| 国产成人精品999在线观看| 欧美黑人性视频| 五月婷婷免费视频| 亚洲欧洲中文日韩久久av乱码| 我的公把我弄高潮了视频| 国产成人免费精品| 在线观看亚洲一区| 99国产精品免费视频| 99久久99久久精品国产片果冰| 亚洲跨种族黑人xxx| 亚洲 小说区 图片区| 久久无码av三级| 精品久久一二三| 国产精品xxx在线观看| 国产精品久久久久久av福利软件 | 美日韩一区二区三区| 国产欧美日韩网站| 欧美激情电影| 久久精品99| 久久中文字幕一区二区| 国产成人精品视频| 美女高潮在线观看| 久久成人精品视频| 成人精品一区二区三区免费 | 亚洲黄色免费观看| 亚洲一级在线观看| 国产精品嫩草影院俄罗斯| 久久精品人人做人人综合 | 亚洲第一天堂| 亚洲成人第一| 欧美在线关看| 粉嫩高清一区二区三区精品视频 | 91国产美女视频| 欧美人与禽性xxxxx杂性| 色偷偷88888欧美精品久久久| 国产内射老熟女aaaa∵| 亚洲一级不卡视频| 丰满少妇被猛烈进入一区二区| 国产成人亚洲综合色影视| 精品少妇一区二区三区在线| 欧美激情91| 在线观看国产一区| 日本久久黄色| 日韩一区不卡| 91蝌蚪精品视频| 91传媒在线免费观看| 午夜精品久久久久久毛片| 国产精品久久久久久久7电影| 成人黄色网址| 中国人与牲禽动交精品| 国产在线三区| 国产亚洲一区精品| 国产黄在线观看免费观看不卡| 欧美一区二区成人| 国产免费黄色片| 欧美变态tickling挠脚心| 精品人妻一区二区三区含羞草| 色综合久久综合| 亚洲二区在线播放| 亚洲视频精选在线| 国产精品18在线| 综合久久一区二区三区| 五月天av网站| 一区二区三区在线视频免费观看| 福利视频一二区| 亚洲高清影视| 男人的天堂avav| 亚洲va久久久噜噜噜久久| 国产一区免费在线| 香蕉视频一区二区三区| 日本一区二区在线视频观看| 日韩美脚连裤袜丝袜在线| 牛人盗摄一区二区三区视频| 国产欧美日韩视频在线| 国产精品一区二区欧美| 影音先锋欧美激情| 欧美中文娱乐网| 97精品一区二区| 在线观看三级网站| 最新日韩在线| 国产福利在线免费| 日韩国产综合| 在线精品亚洲一区二区| 好吊日精品视频| 亚洲一区二区三区精品动漫| 日本三级一区| 97视频在线观看成人| 欧美成人资源| 成人久久久久久| 91大神精品| 久久视频在线观看中文字幕| 国产精品成人a在线观看| 日本在线观看一区| 香港欧美日韩三级黄色一级电影网站| 欧美日韩一区二区三区在线视频 | 国产美女18xxxx免费视频| 国产黑丝在线一区二区三区| 天天操精品视频| 99综合电影在线视频| 大胸美女被爆操| 五月天一区二区三区| 亚洲一区二区人妻| 精品国产精品一区二区夜夜嗨| 国产露脸国语对白在线| 欧美色精品天天在线观看视频| 亚洲精品国产无码| 日韩精品一区二区三区视频| 精品无吗乱吗av国产爱色| 欧美另类老女人| а√中文在线8| 久久久久久久久国产| 成人午夜精品| 国产欧美日韩综合精品二区| 精品国产乱码久久久久久果冻传媒 | 国产视频精品在线| 三级视频在线| 久久久久久久久久国产精品| 日韩欧美2区| 国产伦理久久久| 在线中文字幕亚洲| 182午夜在线观看| 91麻豆国产在线观看| 午夜爽爽爽男女免费观看| 色综合天天综合给合国产| 日韩一级片免费看| 欧美成人午夜视频| 国产精品黄色片| 欧美日韩国产不卡在线看| 一本色道久久综合| 韩国三级与黑人| 成人av网站免费观看| 亚洲波多野结衣| 欧美群妇大交群中文字幕| 国产小视频免费在线观看| 午夜精品久久久久久久白皮肤 | 国内精品久久久久久久久电影网| 日韩亚洲视频在线| 亚洲欧美日韩精品一区二区| www.黄色网| 综合久久久久综合| 国产精品久久久久久久免费看| 日韩精品一区二区三区在线播放 | 免费观看一级欧美片| 国产成人免费观看| 国产精品hd| 色婷婷狠狠18禁久久| 亚洲午夜视频在线观看| 精品人妻无码一区二区| 久久999免费视频| 伊人精品综合| 国产97在线 | 亚洲| 99久久国产综合色|国产精品| 在线免费观看麻豆| 欧美特黄级在线| 精品乱码一区二区三四区视频| 日韩少妇与小伙激情| 另类一区二区三区| 亚洲欧美日产图| 在线视频精品| 亚洲精品国产91| 91国偷自产一区二区开放时间| 国产成人免费看一级大黄| 亚洲成人中文字幕| 亚洲欧洲日本韩国| 欧美在线视频二区| 日本不卡的三区四区五区| 色哟哟在线观看视频| 亚洲18色成人| 欧美女子与性| 国产精品情侣自拍| 成人在线免费观看网站| 亚洲爆乳无码专区| 国产女人aaa级久久久级| 一级黄色大毛片| www.午夜精品| 精品亚洲精品| 99久久国产宗和精品1上映| 成人小视频在线| 成年免费在线观看| 最近日韩中文字幕中文| 日韩视频一二区| 日日碰狠狠添天天爽超碰97| 国产精品一区二区x88av| 伊人久久久久久久久久久久久久| 欧美影院一区二区三区| 午夜国产在线视频| 国产精品精品视频| 亚洲人成网www| 在线免费看污网站| 午夜精品久久久久久久久久久| 岳乳丰满一区二区三区| 欧美激情在线狂野欧美精品| 九色精品国产蝌蚪| 你懂的av在线|