angular - NGRX reducer 多个实例的选择器

标签 angular ngrx ngrx-store

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

ngrx 中是否有等效项,或者是否有其他方法来创建这些选择器以与 reducer 的不同实例一起使用?

下面是一个基于我想要完成的 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 的回答对于我给出的人为代码示例来说是有意义的,但如果每个 reducer “实例”具有许多属性或者如果您需要许多“实例”,那么肯定会存在维护问题。在这些情况下,您最终会在单个 reducer 上得到许多准重复的属性(例如“bookIds”、“magazineIds”、“dvdIds”、“microficheIds”等)。

考虑到这一点,我回到了 Redux 文档,并按照它查看了选择器的常见问题解答,特别是 How Do I create a Selector That Takes an Argument .

根据这些信息,我将其放在一起:

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);
}

在某些您知道要使用的 reducer 的组件中:

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

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

关于angular - NGRX reducer 多个实例的选择器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45108947/

相关文章:

typescript - NgRx:如何声明由 Action 创建者创建的 Action 的显式类型?

angular - 关于这个 Angular + ngRx(效果)的建议 - websocket 事件呢?

javascript - 应用程序范围内可访问和可变的变量

javascript - TypeScript 中的 RSA 加密/解密

testing - 使用 jasmine-marbles 的 ngrx/effects 单元测试

angular - @ngrx/store pre-load guard catch 错误

angular6 - 当我在获取数据后调度操作时无限循环/订阅

angular - 在特征内选择数据的 ngrx/entity 问题

javascript - 将div分成2列

angular - jasmine-karma 中的模块 'undefined' 导入了意外值 'DynamicTestModule'