ReactのComponentをどう設計すればいいかという話で最近ちょっと学びがあった
まず以下のコードを見て欲しい
class menuPopup extends React.Component {
...
renderPopup() {
if (this.props.isPopupOpen) {
return <Popup />;
}
return null;
}
render() {
return (
<div>
<button onClick={this.handleButtonClick} />
{this.renderPopup}
</div>
)
}
}
結論から言えばrenderPopup()
なんていう関数はやめようという話
renderPopup()に切り分けてしまう動機
上記のようなコードを僕は大量に生成していた。
なんで切り分けたかというと、
ロジック(ここではif文)がある部分は切り分けたかったから。
僕はもともとrailsでサーバを書いてたので
ついついロジックがある部分はメソッドに切り出したくなってしまった
そして上記のようなコードを書いてしまったのだ
そもそもなぜメソッドに切り出すのか
そもそもバックエンドのコードでロジックをメソッドに切り出すメリットはなんなのかを考えて見ると大きく分けて次の2つあると思う
- 可読性を上げるため
- 変更に強くなるため
まず可読性をあげるということだが、バックエンドのコードはロジックそれ自体ではぱっと見何をしているのかわからないことが多い
しかしメソッド化して名前をつけてあげれば、そのコードが何をしているのか、実際のロジックを見なくても理解することができる。
次に、変更に強くなるというのがどういうことかというと、同じロジックが複数の箇所で使われている場合それをメソッドに切り分けておけば、そのロジックに変更があった場合にそのメソッドの中だけを変更すればよくなるということ
そしてそれをできるだけ細かく役割ごとに分けるほど、変更する理由は減っていき、メンテナンス性が向上する
今回の場合切り出す必要はあるのか?
それぞれについて考えて見る
まず可読性はあがるか
個人的な意見だが、そこまで可読性は変わらないんじゃないかと思う
renderPopupの中で<Popup />
が呼ばれていてこれが直接書いてあっても何をしようといるのか一目でわかる
そもそもHTMLはviewを直接反映しているのであまりに膨大ではない限りそのまま書いてあった方がviewをイメージしやすい
次に変更に強くなるか
これは場合によると思う
このrenderPopup()はともかく、このようなJSXを返す関数を他で使うのであれば関数化することでメンテナンス性が向上する
ただここでひとつ考えるべきなのは、JSXを返す関数とはComponentに他ならないということだ
stateless componentはまさにpureにJSXを返す関数である
つまり、あるJSXを返す関数を複数の場所で使うのであればそれははっきりとComponentとして別ファイルに書き出したほうが管理がしやすくなる
これをレビューで指摘していただいたときはすごく納得した
結論:renderPopup()はやめよう
以上のように考えるとComponentの中にJSXを返す関数を定義するのはよくないのではと思う
他の場所で使わないのであればrender()の中にベタ書きして可読性をあげよう
他の場所でも使いそうならComponentとして切り分けてメンテナンス性をあげよう
だらだら書いたが、最初に見せたような条件分岐の書き方としてはReactのドキュメントにあるようにConditional Renderingの記法を使うのがいいと思う
https://reactjs.org/docs/conditional-rendering.html
class menuPopup extends React.Component {
...
render() {
return (
<div>
<button onClick={this.handleButtonClick} />
{this.props.isPopupOpen &&
<Popup />
}
</div>
)
}
}
可読性もかなりいい
学んだこと
この話を通して学んだことは、ある状況で推奨されている設計はその背景をきちんと理解したほうがいいということだ
今回のように関数での切り分けはある状況ではベストプラクティスが、別の状況では違うかもしれない
設計の判断をするためにも、なぜその設計だといいのかということをちゃんと学ぼうと思った