TimeCrowdのフロントエンドはフルReactで作られています。開発当初は右も左もわからずビジネスロジックやstateを全てコンポーネントに含めてしまっていました。
ただReact + Reduxの開発にも慣れ、コードの規模も大きくなってきたところで、色々と弊害も発生してきており、全体的な設計を考える必要があるのではないかと考え始めました。
こんにちは、台湾行きを1ヶ月後に控えた旅するエンジニアの三宅です。
テスタブルな構成にするために今回はrecomposeを使ってReactのライフサイクルとコンポーネントを分離する方法を紹介したいと思います。
recomposeとは?
まずはrecomposeとはどんなライブラリなのか確認してみましょう。
A React utility belt for function components and higher-order components.
acdlite/recompose: A React utility belt for function components and higher-order components.
function componentsやhigher-order componentsを提供するためのユーティリティライブラリということです。
function componentsとはStateless functional componentsのことでしょうか。Stateless functional componentsについてはいくつか紹介記事があるので参照して下さい。
- 【React】コンポーネントをシンプルに書くためのStateless Functional Componentsについて | maesblog
- メンテナブルな React Component を目指すための小技集 – Qiita
- Stateless な React Component の記法をまとめてみた – Qiita
Stateless functional componentsはシンプルなDOMを返す関数といったところでしょうか。
higher-order componentsについては以下の記事を参考にしてみて下さい。
- Higher-Order Components – React
- ReactのHigher Order Components詳解 : 実装の2つのパターンと、親Componentとの比較 | プログラミング | POSTD
Concretely, a higher-order component is a function that takes a component and returns a new component.
higher-order componentsとはコンポーネントを受け取ってコンポーネントを返す関数のことということです。頭文字を取ってHOCと言いますが、今回は詳細には触れません。
lifecycleを使ってReactのライフサイクルとレンダリングを分離
recomposeのAPIドキュメントを読むとたくさんの関数が用意されていることがわかります。今回はその中からlifecycleを使ってReactのライフサイクルとStateless functional componentsを分離する方法を紹介します。
一般的なReactのComponentは以下のような形になります。
// Home.jsx
import React, { Component } from 'react';
export default class Home extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
doSomething();
}
render() {
return (
<div>This is my home</div>
);
}
}
何の変哲もないコンポーネントです。これをrecomposeを使ってライフサイクルを管理する関数とStateless functional componentsに分離してみたいと思います。
// Home.jsx
function Home(props) {
return (
<div>This is my home</div>
)
}
// HomeWithLifeCycle.js
import { lifecycle, } from 'recompose';
const HomeWithLifeCycle = lifecycle({
componentDidMount() {
doSomething();
},
})(Home);
export default HomeWithLifeCycle;
どうでしょう、Home.jsxはシンプルなDOMを返す関数となり、HomeWithLifeCycle.jsがReactのライフサイクルを管理する役割を担うようになりました。
このようにロジックと描画を分離すれば、デザイナーにStateless functional componentsを書いてもらい、ロジック部分はフロントエンジニアが書くという分業も可能になります。
recomposeを使うメリットとデメリット
最後にrecomposeを使って処理を分離するメリットとデメリットを自分なりにまとめてみたいと思います。
メリット
- 関心事を分離することで、考えなければいけないことが減る
- 一つ一つの処理をシンプルにすることができ、テストが書きやすくなる
- Stateless functional componentsが増えれば再利用性が高くなる
- 単純なDOMを返す関数であればデザイナーに直接作ってもらうことも可能
デメリット
- ルールを決めて整理してコードを書かないと、関連性がわからず混乱の元になる
- ファイルを分割することで管理コストが増大する
まだまだ使い始めたばかりですが、使い方によっては関心事を分離できて、さらにテストもしやくなるのではないかと考えています。
これからユーザーに安定した機能を素早く提供していけるように良いアーキテクチャについて考えていきたいと思います。