redux/examples/shopping_cart を見て学ぶ

redux/examples/shopping-cart at master · reactjs/redux · GitHub

仕様

  • 商品リストとカートがあり、商品をカートに入れることができる

  • 商品は在庫があり、在庫がなくなると、sold out と表示される

  • カートでは合計金額を表示する

state間の連携について

stateとして、商品情報のproductsとカート情報の cartがある。

カートでは商品IDと個数を保持している。

カートで合計金額と取得したい時に、state:cart内には金額の情報がないので、productsから商品の情報を取得する必要がある。

こういった処理をどこに、どうやって書いていくかというのがreduxでよく解っていないポイント。

今回の例では, reducers/index.js に getTotal関数が実装されていて、exportされ、コンポーネントのmapStateToPropsから呼び出されている。

// reducers/index.js内の合計金額を取得する実装

function getQuantity(state, id) {
  return fromCart.getQuantity(state.cart, id)
}

function getProduct(state, id) {
  return fromProducts.getProduct(state.products, id)
}

export function getTotal(state) {
  return getAddedIds(state).reduce((total, id) =>
    total + getProduct(state, id).price * getQuantity(state, id),
    0
  ).toFixed(2)
}

reducerを単純にアクションからstateを生成する役割に加えて、stateからデータを取得する役割を負っている。

複数のstateをまたがったデータを取得する際は、index.jsに定義し、各子stateから必要な情報を取得し、調整して返すようにされている。

この程度の規模のプログラムだと問題なさそうだけど、もう少し大きくなってくるとindex.jsがカオスになりそうなので、もう少し工夫する必要がありそう。

stateの持ち方の工夫

state:productsが単純な配列ではなく、下記のように定義されている。

{
  byId: {}, // id => product のオブジェクト。 state.byId[product_id] で商品データにアクセスできる
  visibilityIds: [] // 商品IDのリスト
}

これは一長一短ありそう。

感想

基本理念以外の部分は結構自由に実装されている印象。

FWに従って思考停止ではなく、作るプログラムに合わせて色々考えて工夫する必要がありそう。