Reactを用いたアプリケーション開発におけるスタイルガイド
自分が参画、または支援に入るプロジェクトで、組織的なガイドなどが存在しない場合に導入するスタイルガイドです。
基本的にはTypeScript Deep DiveのStyleGuideをベースとしながら、React固有のコンポーネントやフックに対するスタイルを定義しています。
スタイルガイド
変数と関数
- 変数と関数名には
camelCase
を使います
クラス
- クラス名には
PascalCase
を使います。
インタフェース
- 名前には
PascalCase
を使います。 - メンバには
camelCaseを
を使います。 - プレフィックスに
I
をつけないでください
タイプ
- 名前には
PascalCase
を使います。 - メンバには
camelCase
を使います。
Enum
- enum名には
PascalCase
を使います - enumメンバには
PascalCase
を使います
null
vs undefined
- 明示的に使用不可能にするために、どちらも使用しないことを推奨します
- 一般的に
undefined
を使用してください(代わりに{valid: boolean, value?: Foo}
のようなオブジェクトを返すことを検討してください) - APIまたは従来のAPIの一部である場合は
null
を使用します -
truthy を使用すると、オブジェクトが
null
またはundefined
であるかどうかをチェックできます -
== null
/!= null
(===
/!==
ではない)を使い、プリミティブにnull
/undefined
をチェックします。これはnull
/undefined
の両方に働きますが、他の falsy 値(例:''
,0
,false
など)では機能しません
null
と undefined
の明示的な使い分け
バックエンドのAPI設計とも関連しますが、例えばREST APIでリソースの一部を更新するPATCHメソッドでは null
と undefined
の明示的な使い分けが必要となるでしょう。
例えば、あるリソースが以下のプロパティを持っているとします。 foo
は必ず値を持ちますが、 bar
は null
(未設定)が許容されます。
{
foo: string;
bar: string | null;
}
このリソースを部分更新するPATCHメソッドのペイロードのインタフェースは以下のようになるでしょう。
{
foo?: string
bar?: string | null
}
プロパティの未設定を undefined
ではなく null
と定義することで、一貫したインタフェースとすることができます。
引用符
- エスケープしない限り、シングルクォート(
'
)を使用することをお勧めします - ダブルクォートを使用できない場合は、バックティック(
`
)を使用してみてください
スペース
-
2
つのスペースを使います。タブではありません
セミコロン
- セミコロンを使用してください
配列
- 配列に
foos: Array<Foo>
の代わりにfoos: Foo[]
として配列にアノテーションをつけます
type
vs interface
- ユニオン型や交差型が必要な場合には
type
を使います -
extend
やimplements
をしたいときは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
を使い、必要に応じてis
やhas
などのプレフィックス、exists
などのサフィックスを付けます
isAvailable
hasReceived
userExists
例外
- HTML要素(aタグやbuttonタグ)をforwardRefしてそれらの要素を透過的に利用する場合、利用側の混乱を避けるため備わっているプロパティをそのまま使います
buttonの
disabled
をisDisabled
にはしません
ファイル名 / ディレクトリ名
-
kebab-case
を用います
TypeScript Deep Diveでは
camelCase
となっていますがgitではデフォルトで大文字と小文字の区別が行われない設定なっているためです
例外
- Reactのコンポーネント、コンテキストを定義しているディレクトリ / ファイルには
PascalCase
を使います
UserList.tsx
UserList/index.tsx
- Reactのフックを定義しているディレクトリ / ファイルには
camelCase
を使い、use
のプレフィックスを付けます
useGetUser.ts
useGetUser/index.ts
Discussion