はじめに
ReactやNext.jsのフロントエンドを実装しています。
見た目部分のデザイン面のコーディングを主に担当しています。
今回は実際最近いただいたレビューから、今後気をつけたいこと注意するべき視点をまとめました。
1.コンポーネントの分け方・設計の観点で気をつけること
コンポーネントの分け方は適切か
- コンポーネントは1つの責任を持つように設計されているか
- 各コンポーネントの責任と役割が分かりやすく設計されているか
before
export const Sample: FC = () => (
<DesignSetCondition value="test">
<Section>
<div>
<p></p>
.
.
.
</div>
</Section>
</DesignSetCondition>
)
↓
after
export const Sample: FC = () => (
<DesignSetCondition value="test">
<Section>
<SampleContents />
</Section>
</DesignSetCondition>
)
上記の例ではSample
コンポーネントは<DesignSetCondition>コンポーネント
にvalueプロパティを渡す処理を行っている。
<SampleContents>コンポーネント
では<DesignSetCondition>
から受け取った"test"という値に基づいた条件付きのレンダリングを行われることが期待される。
結果として、コードの可読性や再利用性、保守性が向上する。
関心の分離(Separation of Concerns, SoC)
ソフトウェア設計の原則の1つであり、複雑なシステムやコードベースを理解しやすく、保守しやすくするための重要な概念のこと。関心の分離では、異なる関心事(concerns)を異なる部分に分離し、それぞれが特定の責任を持つようにする。
コンポーネントを分ける必要があるか
細かく分けすぎてもプロジェクト内で大量のコンポーネントが作成され、管理が複雑になるリスクが生じるので、再利用しやすい単位でのコンポーネント設計を意識する。
1つのファイルに対して1つのコンポーネントが原則
可読性やメンテナンス性といった観点から、1つのファイルに対して1つのコンポーネントを作成する。1つのファイルに別々のコンポーネントをまとめない。
before
export const KvSampleImage1: FC = () => (
<Image
loader={imageLoader}
src="/images/sp/sample.png"
width={200}
height={100}
alt=""
/>
)
export const KvSampleImage2: FC = () => (
<Image
loader={imageLoader}
src="/images/sp/sample2.png"
width={200}
height={100}
alt=""
/>
)
↓
after
export const KvSampleImage1: FC = () => (
<Image
loader={imageLoader}
src="/images/sp/sample.png"
width={200}
height={100}
alt=""
/>
)
export const KvSampleImage2: FC = () => (
<Image
loader={imageLoader}
src="/images/sp/sample2.png"
width={200}
height={100}
alt=""
/>
)
外部ライブラリを使用している場合は、カスタムフックに切り出す
Reactの例では、SliderやModalといったライブラリが直接利用するケースはあまりなく、各サービスやプロジェクトに沿って見た目や挙動などが工夫されている。
そのため、1つのファイルにまとめて直接利用するのではなく、別ファイルでカスタムして定義し、使用するファイルでは利用するだけにする方が保守性を保つことができる。
共通で使用できるロジックである場合はCustom Hookとしてまとめる
独自のフックを作り、カスタムフックにまとめることで、ロジックの記述が重複することを防ぐ。
コンポーネントに分けることで、コンポーネントごとの役割を分離することができ、コードの可読性が高まります。
2.命名の観点で気をつけること
typoしていないか
VSCodeの拡張機能「Code Spell Checker」で一般的なスペルミスを防ぐことができる。
関数名が汎用的すぎないか
「どのような場面で」使用されている関数なのか、理解できることが重要。
誰が見ても理解できる関数・変数名であるかが再度確認。
汎用的すぎるとどこで使用されているか判断しづらく、バグにつながる可能性がある。
大文字・小文字が混ざっていないか
混ざってしまっていないか確認する。
例:型の名前・ファイル・関数の名前
キャメルケース・スネークケースが混ざっていないか
ルールが決まっている場合は合わせて命名する。
3.Reactの基本原則は守れているか
keyは一意であるか
Reactのkey propに配列のindexを使うことは良くない。
同じidは使用しないようにする
IDはデータを識別するために利用されるので、同じIDを利用しないようにする。
before
const HogeInfirmations = [
{
id: '78',
title: 'aaa'
...
},
{
id: '78',
title: 'bbb'
...
},
{
id: '78',
title: 'bbb'
...
},
↓
after
const HogeInfirmations = [
{
id: 1,
productId: '78',
title: 'aaa'
...
},
{
id: 2,
productId: '78',
title: 'bbb'
...
},
{
id: 3,
productId: '78',
title: 'bbb'
...
},
不要なpropsの受け渡しが行われていないか
子コンポーネントで完結するpropsを親コンポーネントから受け取り、不要な受け渡しを行なっていないか。
4.TypeScriptの基本原則を守れているか
型とデータの順番は合っているか
データと型定義のキーの順番は統一し、理解しやすくする。
元となる型があるのなら 新しく型を定義を行わない
ファイル別で新しく型を作ってしまうと、型の定義が重複してしまうので、Pick・Omitを使用して使いたい情報だけを使用するようにする。
また、その際の型の命名は汎用的なものにしないように気をつける。
別のコンポーネントで元となる型の一部を使用した型定義を作成した際に、型情報を読む順序によって型情報への先入観を与えてしまう問題が起こるため。
type HogeType = {
hoge: Hoge[]
}
// 一部だけ使用する
// 名前は汎用的なものにしない
type PickComponentInfirmationType = Pick<
Hoge,
'logoImage' | 'name' | 'linkpath'
>
5.CSSに関する気をつけたいこと
重複していないか・無駄な記述がないか
同じ内容のCSSが繰り返されていたり、不要なコードが存在していないか。
コーディングルールに沿っているか
BEMやFLOCSSなど、設計手法が定められている場合はそこに沿っているか再度確認。
6.実装に関する気をつけたいこと
動作は意図通りか
- アニメーションは想定通りか
- Google Tag ManegerやGA4で計測する値が正しく取れているか
- 想定される全てのパターン・条件を網羅しているか
- 返ってくる値がundefindの場合を想定しているか
など、動作が仕様用通りかどうかも各職能間でしっかり確認することが重要。
7.見た目に関する気をつけたいこと
対象のページの見た目はデザインデータ通りか
文字の大きさ、余白、色は正しいか?
対象外のページの見た目に影響はないか
デザインセットやページだけでなく、クエリパラメーター・条件分岐によって表示を切り分けている箇所はないか?
どの画面幅でも崩れずに表示できているか
画面幅が変化した際、表示が崩れることはないか?
デベロッパーツールや検証ツールで確認。
どのブラウザでもデザインデータ通りに表示できているか
実機で見た際に、表示が崩れることはないか?
特にGoogleChromeでは表示が綺麗でも、実機のSafariで見た際に若干異なっている場合もあるので注意。
文字が複数行になったときのことも想定できているか
デザインデータの特定の(固定の)条件だけではなく、複数行になった場合や条件が変わった場合のことも想定できているか?
特に、文字が多くなった場合の折り返しや余白はもう一度確認。
構造はデザインデータ通りか
デザインデータの構造の作りとコーディングの構造の作りが異なると、意図しない表示に繋がるリスクがある。
デザイン担当者と実装担当者で構造について共通認識を持つ。
まとめ
気をつけるべき箇所は関わっている開発の環境・体制により様々ですが、一般的に気をつけた方が良いことをまとめてみました。
基本的な部分やケアレスミスでレビューを増やさないように意識していきます!