Help us understand the problem. What is going on with this article?

Reactで使う有名なコンポーネントデザインパターン

Reactで使う有名なコンポーネントデザインパターン

by ryokkkke
1 / 20

社内勉強会用のメモ


概要

コンポーネントの概念でアプリケーションを組み立てる際に使えるデザインパターン3種類を紹介。

  1. HOC
  2. Render Props
  3. Compound Components

1. HOC

高階コンポーネント(Higher Order Component)の略称。

高階コンポーネント (higher-order component; HOC) はコンポーネントのロジックを再利用するための React における応用テクニックです。HOC それ自体は React の API の一部ではありません。HOC は、React のコンポジションの性質から生まれる設計パターンです。

具体的には、高階コンポーネントとは、あるコンポーネントを受け取って新規のコンポーネントを返すような関数です。

https://ja.reactjs.org/docs/higher-order-components.html


つまり、HOCとはコンポーネントの一種で、通常のコンポーネントがpropsを受け取ってjsxを返すのとは違い、コンポーネントを受け取ってコンポーネントを返す関数のことを指す。

基本的には以下の条件を満たす関数をHOCと呼ぶ。

  1. 副作用の無い純粋な関数である。
  2. 引数(の一つ)としてコンポーネントを受け取る。
  3. 引数で受け取ったコンポーネントをラップした(内包した)新しいコンポーネントを返す。

利用例

  1. react-reduxのconnect関数
  2. Next.jsのwithRouter関数
  3. next-redux-wrapperのwithRedux関数

などなど。
HOCの名前には、慣習的にwithを接頭辞としてつけることが多い。


有用性

横断的関心事に HOC を適用する

https://ja.reactjs.org/docs/higher-order-components.html#use-hocs-for-cross-cutting-concerns

とあるように、コンポーネント間で横断の(=共通の)処理が存在しそれをDRYにしたい場合に使える。


おそらく HOC とコンテナコンポーネントと呼ばれるパターンの類似性に気づいたでしょう。コンテナコンポーネントは高レベルと低レベルの関心事の責任を分離する戦略の一部です。コンテナはデータ購読や state を管理してコンポーネントに props を渡し、渡された側のコンポーネントは UI の描画などの事柄を取り扱います。HOC はコンテナをその実装の一部として使用します。HOC をパラメータ化されたコンテナコンポーネントの定義であると考えることができます。

https://ja.reactjs.org/docs/higher-order-components.html#dont-mutate-the-original-component-use-composition

つまり、HOCはコンテナの一種と考えることができる。


簡単な実装例

type InjectedProps = {
  isBraveThunders: boolean;
};

const withBraveThunders = function<CP>(Component: React.FunctionComponent<CP>) {
  return (props: InjectedProps & CP) => {
    const { isBraveThunders, ...passThroughProps } = props;

    // isBraveThundersがtrueの場合は、ページ読み込み後に問答無用で川崎ブレイブサンダースの公式ページにリダイレクトする
    React.useEffect(() => {
      if (!isBraveThunders) return;

      location.href = "https://kawasaki-bravethunders.com/";
    }, [isBraveThunders]);

    return <Component {...passThroughProps as any} />;
  };
};

type ChildProps = {
  hoge: number;
  piyo: number;
};

const ChildComponent = (props: ChildProps) => (
  <div>
    <div>{props.hoge}</div>
    <div>
      <div>{props.piyo}</div>
    </div>
  </div>
);

withBraveThunders(ChildComponent);


ちなみにconnectとかは正確に言うと

connect.js
export const SharedLiveSPContainer = connect(
  mapStateToProps,
  mapDispatchToProps,
)(SharedLiveSPComponent);

connect(options)(component) という感じで「connect関数がHOCを返している」と言えるね。


https://ja.reactjs.org/docs/higher-order-components.html

細かい注意点とかはReactの公式ドキュメントも読もう。


2. Render Props

“レンダープロップ (render prop)”という用語は、値が関数である props を使って、コンポーネント間でコードを共有するためのテクニックを指します。

https://ja.reactjs.org/docs/render-props.html


render-props.js
<DataProvider render={data => (
  <h1>Hello {data.target}</h1>
)}/>

const DataProvider = (props) => (
  <div>{props.render({ target: "hoge" })}</div>
);

jsxを返す関数をpropsとして受け取り、それをrender内で実行するコンポーネントのこと。


有用性

横断的関心事にレンダープロップを使う

HOCと同じで、コンポーネント間で共通の処理などに使う。
また、DIっぽいイメージでレンダリングする内容を外から受け取りたい場合にも使える。


レンダープロップの興味深い点として、多くの高階コンポーネント (HOC) がレンダープロップを使った通常のコンポーネントによって実装可能ということが挙げられます。

基本的にはHOCでできることはRender Propsでも実装できそう。


例ではprops名にrenderを使ってるけど、これは別にReactが用意している特別な何かなわけではないので、props名はなんでも良い。
renderだけだと意味がわからない場合は renderHoge みたいな感じにしても良い。

つまり、childrenというprops名でもOKで、Reactではchildrenというpropsはjsxで子要素として表現できるため、

render-props2.js
<DataProvider>
  {data => (
    <h1>Hello {data.target}</h1>
  )}
</DataProvider>

const DataProvider = (props) => (
  <div>{props.children({ target: "hoge" })}</div>
);

さっきの例はこれでも良い。


react-virtualized(Reactで無限スクロールを実現するライブラリ)ではこの形が使われてる。

AutoSizer.js
// Render your list
ReactDOM.render(
  <AutoSizer>
    {({ height, width }) => (
      <List
        height={height}
        rowCount={list.length}
        rowHeight={20}
        rowRenderer={rowRenderer}
        width={width}
      />
    )}
  </AutoSizer>,
  document.getElementById('example')
);

https://github.com/bvaughn/react-virtualized/blob/master/docs/AutoSizer.md


https://ja.reactjs.org/docs/render-props.html

Reactのドキュメント読もう。


3. Compound Component


参考

https://kentcdodds.com/blog/advanced-react-component-patterns
コンポーネントのデザインパターン色々

  • Compound Components
  • Higher Order Components
  • Render Props
  • Prop Collections and Getters
  • State Initializers
  • Controlled Components
  • Provider

後ほど色々見てこう。

ryokkkke
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした