react 開發規範

chidaozhi發表於2023-01-30

1.基本規則

• 一個檔案宣告一個元件: 儘管可以在一個檔案中宣告多個 React 元件,但是最好不要這樣做;推薦一個檔案宣告一個 React 元件,並只匯出一個元件;

• 使用 JSX 表示式: 不要使用 React.createElement 的寫法;

• react 18儘量使用函式元件。

2.命名規範

副檔名: 用 .tsx 作為元件副檔名。

檔名: 用大駝峰作為檔名,如:ReservationCard.tsx

引數命名: React 元件用大駝峰,元件的例項用小駝峰。eslint: [react/jsx-pascal-case](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md)

// bad
import reservationCard from './ReservationCard';

// good
import ReservationCard from './ReservationCard';

// bad
const ReservationItem = <ReservationCard />;

// good
const reservationItem = <ReservationCard />;

元件命名: 檔名作為元件名。例如:ReservationCard.jsx 應該用 ReservationCard 作為引數名。 然而,對於一個資料夾裡的跟元件,應該用 index.jsx 作為檔名,同時用資料夾名作為元件名

// bad
import Footer from './Footer/Footer';

// bad
import Footer from './Footer/index';

// good
import Footer from './Footer';

高階元件HOC命名: 用高階元件名和傳入的元件名組合作為生成的元件的 displayName。 舉個例子,一個高階元件 withFoo(), 當傳入一個元件 Bar 應該生成一個新的元件,他的 displayName 屬性是 withFoo(Bar)。

Why? 元件的 displayName 可以用於開發者工具或者錯誤資訊中,同時還有一個值可以清晰的表達這種元件關係,這可以幫助人們理解到底發生了什麼

// bad
export default function withFoo(WrappedComponent) {
  return function WithFoo(props) {
    return <WrappedComponent {...props} foo />;
  }
}

// good
export default function withFoo(WrappedComponent) {
  function WithFoo(props) {
    return <WrappedComponent {...props} foo />;
  }

  const wrappedComponentName = WrappedComponent.displayName
    || WrappedComponent.name
    || 'Component';

  WithFoo.displayName = `withFoo(${wrappedComponentName})`;
  return WithFoo;
}

Props 命名: 避免用 DOM 元件的屬性名錶達不同的意義
Why? 人們期望 style、 className 這種屬性代表一個明確的意義。 為應用程式的一個子集改變此API會使程式碼的可讀性降低,維護性降低,並可能導致錯誤。

// bad
<MyComponent style="fancy" />

// bad
<MyComponent className="fancy" />

// good
<MyComponent variant="fancy" />

3.對齊

對 JSX 語法使用這些對齊風格。 eslint: react/jsx-closing-bracket-location react/jsx-closing-tag-location

// bad
<Foo superLongParam="bar"
     anotherSuperLongParam="baz" />

// good
<Foo
  superLongParam="bar"
  anotherSuperLongParam="baz"
/>

// 如果能放在一行,也可以用單行表示
<Foo bar="bar" />

// Foo 裡面的標籤正常縮排
<Foo
  superLongParam="bar"
  anotherSuperLongParam="baz"
>
  <Quux />
</Foo>

// bad
{showButton &&
  <Button />
}

// bad
{
  showButton &&
    <Button />
}

// good
{showButton && (
  <Button />
)}

// good
{showButton && <Button />}

4.引用

在 JSX 屬性中用雙引號("),但是在js裡用單引號(')。eslint: jsx-quotes
Why? 正常的 HTML 屬性也通常使用雙引號而不是單引號,所以 JSX 屬性也使用這個約定。

// bad
<Foo bar='bar' />

// good
<Foo bar="bar" />

// bad
<Foo style={{ left: "20px" }} />

// good
<Foo style={{ left: '20px' }} />

5.屬性

props 用小駝峰

// bad
<Foo
  UserName="hello"
  phone_number={12345678}
/>

// good
<Foo
  userName="hello"
  phoneNumber={12345678}
/>

如果 prop 的值是 true 可以忽略這個值,直接寫 prop 名就可以。 eslint: react/jsx-boolean-value

// bad
<Foo
  hidden={true}
/>

// good
<Foo
  hidden
/>

// good
<Foo hidden />

避免用陣列下標作為 key 屬性,推薦用穩定的 ID
Why? 不使用穩定杆的 ID is an anti-pattern 會對元件效能產生消極影響,並且元件狀態容易出現問題。 如果陣列元素可能會發生變化,我們不推薦使用下標作為key。

// bad
{todos.map((todo, index) =>
  <Todo
    {...todo}
    key={index}
  />
)}

// good
{todos.map(todo => (
  <Todo
    {...todo}
    key={todo.id}
  />
))}

6.關於Refs 請勿過度使用

詳見react官方檔案Refs and the DOM
Refs 轉發

7.Hook 規則

只在最頂層使用 Hook

不要在迴圈,條件或巢狀函式中呼叫 Hook, 確保總是在你的 React 函式的最頂層呼叫他們。遵守這條規則,你就能確保 Hook 在每一次渲染中都按照同樣的順序被呼叫。這讓 React 能夠在多次的 useState 和 useEffect 呼叫之間保持 hook 狀態的正確。(如果你對此感到好奇,我們在下面會有更深入的解釋。)

只在 React 函式中呼叫 Hook

不要在普通的 JavaScript 函式中呼叫 Hook。你可以:

✅ 在 React 的函式元件中呼叫 Hook

✅ 在自定義 Hook 中呼叫其他 Hook

遵循此規則,確保元件的狀態邏輯在程式碼中清晰可見。

8.狀態管理規範

約定:

  1. 當我們專案中複雜程度較低時,建議只用state就可以了
  2. 如果僅僅因為存在多層傳遞資料的場景,不建議使用mobx或redux,可使用context解決
  3. 如果僅僅因為誇路由資料共享,不建議使用mobx或redux,可使用context或者路由傳參解決
  4. 如果業務複雜,需要使用第三方狀態管理解決複雜度,看下一條
  5. 當專案複雜度一般,小規模團隊或開發週期較短、要求快速上線時,推薦使用mobx
  6. 當專案複雜度較高,團隊規模較大或要求對事件分發處理可監控可回溯時,推薦使用redux,可嘗試使用 rematch或@reduxjs/toolkit,減少模板程式碼
  7. 如果後端資料符合REST風格且資料格式統一且重複資料較多,推薦使用扁平化處理資料,參考normalizr,eg: twitter 知乎

9.目錄結構

├─package-lock.json
├─package.json ------------ // 專案配置
├─postcss.config.js ------- // postcss 配置
├─public ------------------ // 公開目錄
│ ├─favicon.ico
│ └─index.html
├─README.md ---------- // 專案說明
└─src --------------------- // 原始碼目錄
├─App.tsx --------------- // 根元件
├─assets ---------------- // 靜態資源目錄
│ └─images -------------- // 圖片目錄
│     └─logo.png ------ // logo 圖片
│ └─svg -------------- // 圖示目錄
│     └─logo.svg ------ // logo 圖片
├─components ------------ // 公共元件目錄
│ └─Menu ---------------- // 公共元件
│   ├─index.tsx ---------- // 元件檔案
│   └─index.scss ------ // 元件樣式
├─constants ---------------- // 專案常量
│ └─index.ts
├─libs ------------------ // 第三方庫目錄
├─index.tsx --------------- // 主入口
├─router ---------------- // 路由配置
│ └─index.tsx
├─store ----------------- // 狀態管理
│ ├─module.ts // 模組
│ └─index.ts // 入口
├─tests ----------------- // 測試目錄
├─utils ----------------- // 工具目錄
│ ├─a.ts
│ └─index.ts
└─pages ----------------- // 檢視目錄
  └─Home ---------------- // 頁面元件
    ├─components -------- // 子元件目錄
    │ └─Header
    │   ├─index.tsx
    │   └─index.scss
    └─index.tsx ---------- // 元件主體

10.一切儘量遵循官方檔案

狀態提升 - 多個元件資料變化(遵循原則:依靠自上而下的資料流,而不是嘗試在不同元件間同步 state)
React哲學
Effect使用注意

參考

https://jdf2e.github.io/jdc_f...
https://zh-hans.reactjs.org/d...
https://juejin.cn/post/702392...

相關文章