2017-06-07 17 views
2

多くの減算ロジックを重複排除する必要がある地点に構築されたReact/Reduxアプリをリファクタリングしています。私はHigh Order Reducersを見てきましたが、私が彼らを私のために働かせる方法を頭に入れて苦労しています。ここで高次減算器を使用した減額アクションロジックの重複解消

は例です:

reducers.js

import components from './entities/components'; 
import events from './entities/events'; 
import items from './entities/items'; 

const entities = combineReducers({ 
    components, 
    items, 
    events, 
}); 

私はnormalizrを使用しています。私の状態がどのように見えるかの考えがあります。この例では、イベントはコンポーネントまたはアイテムに属することができることを知っていますが、それ以外の場合は区別できます。

{ 
    entities: { 
    components: { 
     component_1: { 
     events: ['event_1'], 
     }, 
    }, 
    items: { 
     item_1: { 
     events: ['event_2'], 
     }, 
    }, 
    events: { 
     event_1: { 
     comment: "foo" 
     }, 
     event_2: { 
     comment: "bar" 
     } 
    } 
    } 
} 

私はすべての3つのレデューサーにEVENT_ADDアクションタイプを使用しています。ロジックはのcomponent.jsitem.js(下記)と同じですが、2つのタイプもそれぞれのタイプに固有の独立したアクションを持っています。

Immutable.jsの.has()関数を使って、間違った場所にイベントを追加すると、ターゲットIDがその部分に存在するかどうかを確認できます。

export default (state = getInitState('component'), action) => { 
    switch (action.type) { 
    case EVENT_ADD: 
     return state.has(action.targetId) ? 
     state.updateIn(
      [action.targetId, 'events'], 
      arr => arr.push(action.event.id) 
     ) : 
     state; 

    [...] 
    } 
} 

event.js では、私は状態のその部分にイベントの内容を追加するだけでなく、ここでEVENT_ADDを使用しています。これは私がイベントの両方EVENT_ADD_COMPONENTEVENT_ADD_ITEMを使用すること(

  1. 使用別々のアクションタイプADD_EVENT_${entity}:上位減速の

    export default (state = getInitState('events'), action) => { 
        switch (action.type) { 
        case EVENT_ADD: 
         return state.set(action.event.id, fromJS(action.event)); 
    
        [...] 
        } 
    } 
    

    私の理解では、私は、次のいずれかまたは両方を行う必要があるということです。 js親に関係なくイベントを作成してください)

  2. bottom of the docsで示されているように、私の主要減速機の名前でフィルターをかけると、私のinitialStateと動作を区別する方法が分かりません私は両方のための減速剤を共有している場合、コンポーネントとアイテムに固有です。

それは私が私がADD_EVENTのようなアクションのためのコンポーネントと項目の間のロジックを共有することができ、いくつかのsharedReducer.jsをしたいようになど、DELETE_EVET、そうです。そしてまた、各エンティティのための2つの独立した減速を持っています。私はこれをどのように達成できるのか、どんなデザインパターンが最善であるかは分かりません。

ガイダンスをいただければ幸いです。ありがとうございました!

答えて

3

"higher-order $ THING"という語句は、一般に、 "引数として$ THINGを使用し、そして/または新しい$ THINGを返す関数"を意味します( "$ THING"は通常 "function" "、"減速剤 "など)。したがって、「高次減速器」は、いくつかの引数をとり、減速器を返す関数です。

あなたがリンクしているセクションでは、最も一般的な高次減速機の例は、IDやアクションタイプや部分文字列のような何らかの識別値を取り、その区別値を使用する新しい減速関数を返す関数です実際にいつ応答するのかを知る。そうすれば、同じ機能の複数のインスタンスを作成することができます。ロジックの残りの部分が同じであっても、「正しい」ものだけが特定のアクションに応答します。

あなたは一般的に正しい軌道に乗っているようですが、共有ロジックを構成する方法はいくつかあります。

一つのアプローチは、明示的に最初の「一般的な」行動を探し、その減速を実行することで、その後、具体的な例を探しかもしれません:

export default (state = getInitState('events'), action) => { 
    // First check for common cases 
    switch(action.type) { 
     case EVENT_ADD: 
     case OTHER_COMMON_ACTION: { 
      state = sharedReducer(state, action); 
      break; 
     }   
    } 

    switch(action.type) { 
     case EVENT_ADD: 
     case EVENTS_SPECIFIC_ACTION: { 
      return eventsSpecificReducer(state, action); 
     } 
    } 

    return state; 
} 

別のアプローチは、reduce-reducersユーティリティのようなものを使用するかもしれません、

const entities = combineReducers({ 
    components : reduceReducers(componentsReducer, sharedReducer), 
    items : reduceReducers(itemsReducer, sharedReducer) 
    events, 
}); 

うまくいけば、あなたは正しい方向にいくつかのポインタを与える:Structuring Reducers - Beyond combineReducersセクションに示されているように。より多くの質問がある場合は、ここで質問するか、Discord - inviteリンクのReactifluxチャットチャンネルでhttps://www.reactiflux.comにお気軽にお問い合わせください。 (注:私はReduxのメンテナー、その著者の"Structuring Reducers" docs section、Reactifluxの管理者です。)

+1

これは完璧です。 'reduce-reducers'は間違いなく私が心に留めていたものですが、別のパッケージの必要性を排除するための最初の提案を取り除くことができるかどうかがわかります。答える時間をとってくれてありがとう! – aesterisk

0

高次のレデューサーの周りに私の頭を包んでいます。より高次の関数やコンポーネントを記述した経験があっても、減速器には多くの制約があり、難しくなっています。

私はこのような解決策を考え出した:メインの「トリック」はその初期状態を取得し、それにプロパティを追加するために、未定義の状態でラッパー減速を呼び出し、そして結果という新しい状態を渡している

export default function withSomething(reducer) { 
    const initialState = { 
     something: null, 
     ...reducer(undefined, {}), 
    }; 

    return function (state = initialState, action) { 
     let newState = state; 

     switch (action.type) { 
      case actionTypes.SET_SOMETHING: 
       newState = { 
        ...state, 
        something: action.something, 
       }; 
       break; 
      default: 
     } 

     return reducer(newState, action); 
    }; 
} 

HORのアクションハンドリングからラップされたレデューサーまで。 newState!= switchステートメントの後にステートがある場合、ラップされたレデューサーを呼び出さないように最適化することができますが、この方法は、ラップされたレデューサーのハンドルと、既に処理されたアクションを潜在的に可能にし、状態。