📖

Reactを用いたアプリケーション開発におけるスタイルガイド

2024/01/08に公開

自分が参画、または支援に入るプロジェクトで、組織的なガイドなどが存在しない場合に導入するスタイルガイドです。
基本的にはTypeScript Deep DiveStyleGuideをベースとしながら、React固有のコンポーネントやフックに対するスタイルを定義しています。

スタイルガイド

変数と関数

  • 変数と関数名には camelCase を使います

https://basarat.gitbook.io/typescript/styleguide#variable-and-function

クラス

  • クラス名には PascalCase を使います。

https://basarat.gitbook.io/typescript/styleguide#class

インタフェース

  • 名前には PascalCase を使います。
  • メンバには camelCaseを を使います。
  • プレフィックスに I をつけないでください

https://basarat.gitbook.io/typescript/styleguide#interface

タイプ

  • 名前には PascalCase を使います。
  • メンバには camelCase を使います。

https://basarat.gitbook.io/typescript/styleguide#type

Enum

  • enum名には PascalCase を使います
  • enumメンバには PascalCase を使います

https://basarat.gitbook.io/typescript/styleguide#enum

null vs undefined

  • 明示的に使用不可能にするために、どちらも使用しないことを推奨します
  • 一般的に undefined を使用してください(代わりに {valid: boolean, value?: Foo} のようなオブジェクトを返すことを検討してください)
  • APIまたは従来のAPIの一部である場合は null を使用します
  • truthy を使用すると、オブジェクトが null または undefined であるかどうかをチェックできます
  • == null / != null ( === / !== ではない)を使い、プリミティブに null / undefined をチェックします。これは null / undefined の両方に働きますが、他の falsy 値(例: '' , 0 , false など)では機能しません

https://basarat.gitbook.io/typescript/styleguide#null-vs.-undefined

nullundefined の明示的な使い分け

バックエンドのAPI設計とも関連しますが、例えばREST APIでリソースの一部を更新するPATCHメソッドでは nullundefined の明示的な使い分けが必要となるでしょう。
例えば、あるリソースが以下のプロパティを持っているとします。 foo は必ず値を持ちますが、 barnull (未設定)が許容されます。

{
  foo: string;
  bar: string | null;
}

このリソースを部分更新するPATCHメソッドのペイロードのインタフェースは以下のようになるでしょう。

{
  foo?: string
  bar?: string | null
}

プロパティの未設定を undefined ではなく null と定義することで、一貫したインタフェースとすることができます。

引用符

  • エスケープしない限り、シングルクォート( ' )を使用することをお勧めします
  • ダブルクォートを使用できない場合は、バックティック( ` )を使用してみてください

https://basarat.gitbook.io/typescript/styleguide#quotes

スペース

  • 2 つのスペースを使います。タブではありません

https://basarat.gitbook.io/typescript/styleguide#spaces

セミコロン

  • セミコロンを使用してください

https://basarat.gitbook.io/typescript/styleguide#semicolons

配列

  • 配列に foos: Array<Foo> の代わりに foos: Foo[] として配列にアノテーションをつけます

https://basarat.gitbook.io/typescript/styleguide#array

type vs interface

  • ユニオン型や交差型が必要な場合には type を使います
  • extendimplements をしたいときは interfaceを 使います
  • 上記の理由がなければ、特段の差異はありません

https://basarat.gitbook.io/typescript/styleguide#type-vs.-interface

== or ===

どちらもTypeScriptユーザーにとってほとんど安全です
JavaScriptの慣習、TypeScriptのコードベースでは === が使われていることから、私は === を推奨します。

コンポーネント

Reactのコンポーネントです。

  • 名前には PascalCase を使います
UserList
  • propsのインタフェース名にはコンポーネント名に Props のサフィックスを付けます
UserListProps

const users: UserListProps['users'] のように利用する側がそのコンポーネントのpropsの型に容易にアクセスできるようにするためです。

  • propsのイベントハンドラとなるメンバはイベント名に on のプレフィックスを付けます
onClick
  • 機能を提供するコンポーネントのpropsのメンバ名は、内部実装を外部に知られないようにします

フォームなどの場合、 onSaveButtonClick ではなく onSubmit とします。
フォームの場合、キーボードによるイベント発生が存在するためです。
デザイン変更などで、ボタンがSaveButtonではなくなる可能性があるためです。

  • フォームを持つモーダルダイアログなどでは、変更が保存されていない状態でのクローズをキャンセルするといった要求があります。そのような場合、イベントハンドラは「閉じることが要求された」というような名称とします
onRequireClosing

イベントハンドラ

  • イベントハンドラにはイベントの名称に on もしくは handle のプレフィックスを付けます

慣習的には handle を付けることが一般的なようですが、私はpropsに合わせる形で on を用います。

  • 子コンポーネントのイベントハンドラに渡す変数を定義する場合、 on とイベント名の間にコンポーネント内で識別できる名前を追加した名称とします
onDeleteDialogRequireClosing

コンテキスト

Reactのコンテキストです。

  • 名前には PascalCase を使い、 Context のサフィックスを付けます
AuthContext
  • プロバイダ名には PascalCase を使い、 ContextProvider のサフィックスを付けます
AuthContextProvider
  • プロバイダのpropsのインタフェース名にはプロバイダ名に Props のサフィックスを付けます。
AuthContextProviderProps

フック

Reactのフックです。

  • 名前には camelCase を使い、 use のプレフィックスを付けます
useGetUser
  • オプショナルなど含む複雑な引数を要求する場合 params オブジェクトを引数とし、 インターフェース名には PascalCase を使ったフック名に Params のサフィックスを付けます
UseGetUserParams
  • 複数の戻り値がある場合はオブジェクトとして返し、 インターフェース名には PascalCase を使ったフック名に Value のサフィックスを付けます
UseGetUserValue
  • 複雑なフックのインターフェースは、例として useGetUser: (params: UseGetUserParams) => UseGetUserValue のようになります。

boolean型のプロパティや変数

  • 名前には camelCase を使い、必要に応じて ishas などのプレフィックス、 exists などのサフィックスを付けます
isAvailable
hasReceived
userExists

例外

  • HTML要素(aタグやbuttonタグ)をforwardRefしてそれらの要素を透過的に利用する場合、利用側の混乱を避けるため備わっているプロパティをそのまま使います

buttonの disabledisDisabled にはしません

ファイル名 / ディレクトリ名

  • kebab-case を用います

TypeScript Deep Diveでは camelCase となっていますがgitではデフォルトで大文字と小文字の区別が行われない設定なっているためです

例外

  • Reactのコンポーネント、コンテキストを定義しているディレクトリ / ファイルには PascalCase を使います

UserList.tsx
UserList/index.tsx

  • Reactのフックを定義しているディレクトリ / ファイルには camelCase を使い、 use のプレフィックスを付けます

useGetUser.ts
useGetUser/index.ts

Discussion