はじめに
業務でReactを利用していますが、高階コンポーネントについて学んだことを備忘録を兼ねて投稿します。
高階コンポーネントとは
あるコンポーネントを受け取って、新しいコンポーネントを返す関数です。
高階関数のコンポーネント版といった感じです。
// 公式ドキュメント
const EnhancedComponent = higherOrderComponent(WrappedComponent);
// react-redux
export default connect(mapStateToProps, mapDispatchToProps)(Component);
// react-router
export default withRouter(Component);
どういうときに使うのか
横断的関心事を処理する方法として利用します。
横断的関心事とはコンポーネントにまたがって処理しなければならない要素の事で、以下のような事柄を指します。
- 認可・ログイン状態
- ログ・トラッキング
- 例外・エラー処理
例えばreact-routerでは、ルーティングに必要な機能をコンポーネントのpropsに渡すために、withRouterという関数が用意されています。
以下がwithRouterの実装ですが、ReactのContext APIを使い、ラッピングしたコンポーネントに対してRouterContextから購読した値をpropsに渡しているのがわかるかと思います。
/**
* A public higher-order component to access the imperative API
*/
function withRouter(Component) {
const displayName = `withRouter(${Component.displayName || Component.name})`;
const C = props => {
const { wrappedComponentRef, ...remainingProps } = props;
return (
<RouterContext.Consumer>
{context => {
invariant(
context,
`You should not use <${displayName} /> outside a <Router>`
);
return (
<Component
{...remainingProps}
{...context}
ref={wrappedComponentRef}
/>
);
}}
</RouterContext.Consumer>
);
};
...
return hoistStatics(C, Component);
}
まとめ
高階コンポーネントは、Reactのメジャーな周辺ライブラリでも採用されているテクニックですので、今後機会があれば利用したいと思います。
今まで横断的関心事にはミックスインが利用されてきましたが、こちらは現在推奨されない実装のようですね。別途記事にしたいと思います。
https://ja.reactjs.org/blog/2016/07/13/mixins-considered-harmful.html
参照