-
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 帳票 要件定義 設計 電力小売業界