2017-07-14 22 views
1

我有一個reducer用於搜索,並意識到它需要用於多個不相關的搜索組件。因此,通過查看Redux文檔,我發現了更高階的reducers(http://redux.js.org/docs/recipes/reducers/ReusingReducerLogic.html#customizing-behavior-with-higher-order-reducers)(ngrx中的meta reducer)的概念,並使用它來創建我的搜索簡化器的2個「實例」。然後,我在相同的文檔中發現,這看起來與選擇器一起工作,但實際上存在備忘錄問題(http://redux.js.org/docs/recipes/ComputingDerivedData.html#accessing-react-props-in-selectors)。該文章引用了一個名爲'mapStateToProps'的函數,它似乎是React將商店數據連接到組件的具體方式(如果我理解正確的話......)。NGRX reducer的多個實例的選擇器

在ngrx中是否有等價物,或者是否有另一種方法創建這些選擇器來處理reducer的不同實例?

下面是基於什麼我試圖完成NGRX示例應用程序輕度人爲的例子:

減速/ searchReducer.ts:

export interface State { 
    ids: string[]; 
    loading: boolean; 
    query: string; 
}; 

const initialState: State = { 
    ids: [], 
    loading: false, 
    query: '' 
}; 

export const createSearchReducer = (instanceName: string) => { 
    return (state = initialState, action: actions.Actions): State => { 
    const {name} = action; // Use this name to differentiate instances when dispatching an action. 
    if(name !== instanceName) return state; 

    switch (action.type) { 
     //... 
    } 
    } 
} 

減速/ index.ts:

export interface State { 
    search: fromSearch.State; 
} 

const reducers = { 
    search: combineReducers({ 
    books: searchReducer.createReducer('books'), 
    magazines: searchReducer.createReducer('magazines') 
    }), 
} 


export const getSearchState = (state: State) => state.search; 

// (1) 
export const getSearchIds = createSelector(getSearchState, fromSearch.getIds); 

我相信上面的getSearchIds選擇器需要能力以某種方式指定它正在訪問的搜索Reducer的哪個實例。 (奇怪的是,在我的代碼似乎工作,但我不知道它如何知道從哪裏選擇,我認爲它有在Redux文檔中討論的memoization問題)。

回答

0

雖然凱文的答案對於我給出的人爲代碼示例是有意義的,但如果每個reducer的「實例」有很多屬性或者需要多個「實例」,肯定會有維護問題。在這些情況下,您會在單個縮減器(例如'bookIds','magazineIds','dvdIds','microficheIds'等)中得到許多準重複屬性。考慮到這一點,我回到了Redux文檔,並按照選擇器的FAQ,特別是How Do I create a Selector That Takes an Argument

從這些信息中,我把這個在一起:

減速器/指數。TS:

export const getBookSearchState = (state: State) => state.search; 
export const getMagazineSearchState = (state: State) => state.search; 

// A function to allow the developer to choose the instance of search reducer to target in their selector. 
export const chooseSearchInstance = (instance: string): ((state: State) => searchReducer.State) => { 
    switch(instance) { 
     case 'books': { 
      return getBookSearchState; 
     } 
     case 'magazines': { 
      return getMagazineSearchState; 
     } 
    } 
} 

// Determines the instance based on the param and returns the selector function. 
export const getSearchIds = (instance: string) => { 
    const searchState = chooseSearchInstance(instance); 
    return createSelector(searchState, state => state.ids); 
} 

在某些部件,其中你知道你要使用的減壓器:

//... 
class SearchComponent { 
    @Input() 
    searchType: string = 'books'; 
    ids: Observable<number>; 

    constructor(private store: Store<fromRoot.State>) {  
     this.store.select(fromRoot.getSearchIds(searchType)); 
    } 
} 
0

我會推薦重新考慮你這樣做的方式,並使用相同的減速器和另一個開關盒。

與此無關,較新版本的AOT不喜歡使用'=>'來創建您的減速器。而是使用

export function SearchReducer (state : State = initialState, { type, payload }){ 
    switch (type) { 
     //cases... 
    } 
} 

,你將不必使用combineReducers,你可以打造出你的減速對象

let reducers = { 
    search: SearchReducer 
} 

說你的狀態是接口狀態類型的允許您在打字的優勢。

+0

你能對你做另一個開關盒答案擴大?這聽起來像你的意思是使狀態界面的重複屬性。但是,這聽起來並不乾燥,使重複的​​屬性和在不同的switch語句中使用相同的cod。 – Mike

+0

我認爲最好在減速器內有一個額外的屬性而不是額外的減速器 – Kevin