-                                        
                                        - React のHOC(高次コンポーネント)の使い所 2: Inheritance Inversion
- 2018年11月2日
- JavaScript
- React
 
前回の記事 では HOC ( High Order Component: 高次コンポーネント)について Props Proxy という手法で実装する方法について触れました。
この記事では、Inheritance Inversion (継承の逆転)という手法での実装を見ていきます。
Inheritance Inversion による実装
前回の記事で触れたかんばんアプリを Inheritance Inversion で実装してみます。
動くコードはこちら。
Props Proxy では WrappedComponent を文字通りラップすることで HOC を実装しました。
Inheritance Inversion では、WrappedComponent を継承します 。
function withSubscription(WrappedComponent, selectData) {
  return class extends WrappedComponent { // 継承したクラスを返却
    ...ソースコードを見るとわかるように、 ラップする側の HOC ファクトリメソッドが WrappedComponent から継承されるのではなく、逆に WrappedComponent を継承するため “Inheritance Inversion”(逆転した継承)と呼ばれます。
これにより WrappedComponent がもつ
- state
- props
- ライフサイクルメソッド1(componentDidMountなど)
- render
といったメソッドやメンバ変数へ直接アクセスできるようになります。
Props Proxy との違い
Props Proxy はラップするコンポーネント WrappedComponent を render メソッド内でそのまま利用していました。つまり、HOC は単純なラッパーとして機能していました。
対して Inheritance Inversion は WrappedComponent を継承することで、コンポーネントのクラス定義自体を拡張・改変することができます。
ユースケース
この違いにより Inheritance Inversion では、Props Proxy とは違った柔軟な実装ができます。
render の処理を乗っ取る
例えば、 render メソッドの呼び出しをジャック2して、 props へ渡されたデータ配列が空の場合に代替テキストを表示させるといったことができます。
props の書き換え
props を動的に追加・更新することができます。
この例では WrappedComponent に input 要素が渡されたとき、name 属性に任意のプレフィックスを付与しています。
注意点として、継承元のオブジェクト(super から取得できるオブジェクト)を直接編集してはいけません3。これを避けるため、
- propsはスプレッド構文4を利用し、新たなオブジェクトを生成して利用する(- wrappedTree.propsを複製し、- newPropsのオブジェクトとマージしている)
- renderメソッドで取得したコンポーネントツリーを- cloneElementで複製する
といったことを行っています。
スプレッド構文によるオブジェクトの複製(下記)は、
次のように従来の方法で行ってももちろん問題ありません。
Inheritance Inversion を利用する上での注意
Inheritance Inversion による実装は、Props Proxy と比べクラスメソッドや state などのメンバ変数に直接アクセスできる分、より柔軟な実装が可能です。 ただそれだけ、ラップするコンポーネントの破壊的操作を可能とします。
- 制御対象でない propsを改変しない
- 継承元の renderメソッドだけでなく、必要なライフサイクルメソッドも呼び出す
といったことに気を遣い、シンプルな実装を心がけましょう。
HOC まとめ
2 つの記事に分けて React の HOC (High Order Component: 高次コンポーネント)と呼ばれる手法について紹介しました。
HOC はコンポーネントを受け取りコンポーネントを返却する関数で、コードの再利用性を高めることができます。
また、2 つの実装手法がありました。
- Props Proxy では コンポーネントのラッパーを生成することで、コンポーネントへ propsの追加やスタイリングなどを行うことができる
- Inheritance Inversion ではコンポーネントのクラスを継承し、各種クラスメソッドやメンバ変数を直接制御できる
HOC を利用する場合、基本は単純なラッパーである Props Proxy で実装できないか考えるべきです。 Inheritance Inversion はより破壊的操作が可能なため、適切なケースを見極めて利用しましょう。
CodePen のサンプルはこちらにまとめています。
この記事を書いた人 : 上田直諒
AWS bluebird css CSV docker docker compose electron ES6 es2015 Git Heroku ITコンサルティング JavaScript justinmind less MongoDB Node.js php PostgreSQL Private Space Promise React react-router reactjs Salesforce scss Selenium Builder selenium IDE Selenium WebDriver stylus TypeScript VirtualBox VisualStudioCode vue vuejs webpack システム開発プロジェクト セキュリティ ワイヤーフレーム 上流工程 卒FIT 帳票 要件定義 設計 電力小売業界
