用于多个 NGRX 减速器实例的选择器



我有一个用于搜索的化简器,并意识到它需要用于多个不相关的搜索组件。因此,通过 Redux 文档,我发现了高阶化简器 (http://redux.js.org/docs/recipes/reducers/ReusingReducerLogic.html#customizing-behavior-with-higher-order-reducers)(ngrx 中的元化简器)的概念,并用它来创建我的搜索化简器的 2 个"实例"。然后我在同一文档中发现,这似乎适用于选择器,但实际上内存(http://redux.js.org/docs/recipes/ComputingDerivedData.html#accessing-react-props-in-selectors)存在问题。那篇文章引用了一个名为"mapStateToProps"的函数,它似乎是 React 将存储数据连接到组件的特定方式(如果我理解正确的话......

ngrx 中是否有等效项,或者是否有另一种方法可以创建这些选择器以使用化简器的不同实例?

下面是一个基于我试图完成的 ngrx 示例应用程序的温和人为示例:

reducers/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) { 
//...
}
}
}

reducers/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 文档中讨论的记忆问题)。

虽然 Kevin的回答对我给出的人为代码示例有意义,但如果每个化简器"实例"具有许多属性或需要许多"实例",则肯定会存在维护问题。在这些情况下,您最终会在单个化简器上得到许多准重复属性(例如,"bookIds"、"magazineIds"、"dvdIds"、"microficheIds"等)。

考虑到这一点,我回到了 Redux 文档,并按照它进入了选择器的常见问题解答,特别是如何创建接受参数的选择器。

根据这些信息,我把这个放在一起:

reducers/index.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));
}
}

我建议重新考虑您的操作方式,并使用相同的减速器并制作另一个开关案例。

与此无关,较新版本的AOT不喜欢使用"=>"来创建化简器。而是使用

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

而且您不必使用组合化简器,您只需构建化简器对象即可

let reducers = {
search: SearchReducer
}

说你的状态是接口状态类型,你可以利用该类型。

相关内容