React + Flux アプリケーションを作るときに知っておきたかった2つのこと
数ヶ月くらいReact + Flux アプリケーションを3〜4つくらい業務で触ってみたら、知っておけば良かったという考え方がいくつかあった。
1. コンポーネントの分け方の考え方
Atomic Designと Presentational and Container Components
各要素をコンポーネントに分割するための考え方のひとつに Atomic Design がある。
パーツをコンポーネント単位で定義していくもの。
Reactのコンポーネントの分ける際にとても役に立つ考え方なので、実装側はこれを基準にデザイナーに考えてもらえるとフロントの実装側はとても助かる。
ただ、デザイナーがこのコンポーネント単位でデザインを起こすのにはそれなりに難易度が高い。
特に全体の設計をしてから、細部に落とし込むやり方に慣れていると大変らしい。
コンポーネント志向の場合、スタイルガイドのようなもので粒度の細かいものをひとつずつ実装してからそれをレイアウトしていく考え方になる。作業フローが逆になる。
一方でデータ設計の目線でみると Presentational and Container Components – Dan Abramov – Medium で書かれている Presentational と Container コンポーネントの分け方の考え方がある。
これは少しでも大きめなReactアプリケーションを作り始めると共感できるもの。stateの管理やらデザインのレイアウトやらをどのコンポーネントが責任を持つかをハッキリさせておくと複数人で開発する場合は良い気がした。特にレビューのコストが下がると思う。
Material-UIを Presentational Component とみなして、試しに実装してみるとわかりやすいと思う。
2. propsのバケツリレーをどう対応するか
Reactアプリケーションを作っていると、props のバケツリレーはどうしておくかも可能ならば事前に決めておきたい。せめて後で分割するときのことに思いを馳せておきたい。
props.children を使いこなす
単純にDOMをツリー上に記載していくと、コンポーネントの汎用性が良くならない。なので、外から内側のDOMを直接代入をしてコンポーネントの分離をしやすくしたりできる。
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; const Item = (props) => { return ( <p>{props.name}</p> ); } const List = (props) => { return ( <div> {props.children} </div> ); } const names = ["a", "b", "c"]; const App = () => { const items = names.map((n, i) => <Item name={n} key={i} />); return ( <List> {items} </List> ) } ReactDOM.render( <App />, document.getElementById('root') );
ポイントはListコンポーネントでItemコンポーネントを記載せずに、props.children
をそのまま表示するように書くこと。
const List = (props) => { return ( <div> <Item name={props.name} /> </div> ); }
モーダルUIなどで外側だけを作って中の要素を丸々propsで渡すなど、外側のレイヤーだけかっちりしているけれど中は汎用的にしたいときはこういったモジュールを実装する。
storeの更新の監視を子で行う
バケツリレーを避けるために、子でstoreデータを監視するのもあり。 ただ、コンポーネントを削除した際にそのstoreデータをきちんと削除するか残し続けるかという選択肢が出てくる。
まとめ
Reactはわかりやすいけれど、Fluxやコンポーネントデザインにまで話が及ぶと明確な正解がないので、ひとつひとつやり方を落とし込んでいくコストが結構かかるのは覚悟必要ってのが最近触った感想です。