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

何をreduxのコンテナにするか

More than 3 years have passed since last update.

redux最近来てるっぽい

reduxとreactを使ってみて、コンテナ(Smart Component)とコンポーネント(Dumb Component)をどう使い分けるかについて考えてみた。

https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.p8sdryhie

上はreduxのcontributor自身による使い分けに付いての解説記事。

各種単体での使ってみた感想はこちら
redux
react

react-redux

reactはJust UIだし、reduxはアプリの状態管理のみが関心ごとなので、reactとreduxを組み合わせるためには、https://github.com/rackt/react-redux をつかいます。

これの役割は何かと言うと、reduxが管理している状態やactionCreatorと、reactのコンポーネントとの橋渡しです。

結合すると、reactコンポーネントで何かイベントが起きる(=reduxのactionCreatorが呼ばれる)と、reduxのアクションに応じてredux管理のアプリの状態が変わり、その結果がreactコンポーネントのpropsに渡って再描画される、というイメージです。この橋渡しはconnectメソッドをつかって行われ、reduxとconnectされたcomponentはコンテナと呼んだりしています。

何をコンテナにするか?

react-reduxのドキュメントを最初読んだときに、データフローをわかりやすくするためにコンテナはネストさせない方が良い、的なことが書いてあり、最初愚直にそれに従いました。その結果どうなったかというと、

class RootComponent extends Component {
  render() {
    const {prop1, prop2, prop3, prop4, prop5} = this.props;
    const {action1, action2, action3, action4, action5} = this.props;
    return (
      <div>
        <SubComponent
            prop1={prop1}
            prop2={prop2}
            prop3={prop3}
            action1={action1}
            action2={action2}
            action3={action3}
        />
        <SubComponent
            prop4={prop4}
            prop5={prop5}
            action4={action4}
            action5={action5}
        />
      </div>
    );
  }
}

connect(
  mapStateToProps,
  mapDispatchToProps
)(RootComponent);

的な感じで、子要素で必要なものを全てルートで渡す事になり、トップのコンポーネントのpropsが肥大化し、さらに深い階層のコンポーネントに必要なアクションもルートで渡す必要があるため、直感的になんでこのアクションを渡しているのかよくわからん感じになります。

データフローがネストしなければ良い

結局ドキュメントで言っているのはデータフローをネストさせるな、という話なので、actionに関しては何も言ってないです。

そんなわけで、渡すpropsのデータがネストしないのであれば、むしろ積極的にコンテナは分けていった方がよさそうです。

たとえば商品リストを一覧で表示し、追加フォームや削除ボタンがあるとします。

containerになるのは、

<ItemList items={items}/>
<NewItemForm addItem={addItem}/>
<DeleteItemButton deleteItem={deleteItem}/>

です。itemsaddItemdeleteItemはそれぞれreduxの管理している状態とアクションです。

ただのコンポーネントしては、

<Item item={item}/>

だけです。itemについては、ItemListからpropsで与えられる物とします。

実装としては、

class ItemList extends Component {
  render() {
    return (
      <div>
        <NewItemForm/>
        {this.props.items.map((item) => {
          return <Item key={item.id} item={item}/>
        })}
      </div>
    );
  }
}

class Item extends Component {
  render() {
    return (
      <div>
        {item.title} {item.price}円 <DeleteItemButton props={item.id}/>
      </div>
    );
  }
}

といった感じになるかと。ルートになるItemListには表示する情報だけを渡し、ネストした要素で必要な削除や追加などのアクションは、アクションだけをreduxとconnectしたコンテナをつかい、必要に応じてpropsでID等を渡します。各コンポーネントに渡されるpropsは直感的にそのコンポーネントに必要そうなものしか与えられないので、ずいぶんわかりやすくなったと思います。

結論

データフローだけネストしないように気をつけて、actionだけがreduxに依存するようなコンポーネントは積極的にcontainerにしていったほうが見通しよくなりそう。

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
ユーザーは見つかりませんでした