对于在 reducer 上调用的每个操作,都会返回新状态。
从问题中的示例代码中,状态只是仪器列表。
没有索引,因此检查工具是否在列表中的唯一方法是搜索整个列表。
但是如果你的州是一本字典呢?此外,如果您将索引列表与字典分开会怎样?
你的状态类型是这样的:
export interface OfferState {
ids: string[];
entities: { [id: string]: IOffer };
};
任何时候执行一个动作,都会返回新的状态。这是 Redux 中的一个重要概念,因为状态永远不能直接改变。实际上,当您编写减速器时,您最好严格执行此操作:(假设您有“提供减速器”和另一个减速器,您可以将它们与 compose 结合为一个:
> export default compose(storeFreeze, combineReducers) ({ oether:
> otherReducer, offers: offersReducer });
在 Redux 中很容易做错事——但是如果你尝试直接改变状态,使用 storeFreeze 会抛出一个错误。关键是动作会改变状态,并产生新的状态。他们不会改变现有的状态——它让我们撤消/重做……等等。
使用上面的示例,我将使用它作为我的提议的减速器:
export interface OfferState {
ids: string[];
entities: { [id: string]: IOffer };
};
export default function(state = initialState, action: Action): OfferState {
switch(action.type){
case OfferActions.INSERT:
const offer : IOffer = action.payload;
return {
ids: [ ...state.ids, action.payload.Instrument ],
entities: Object.assign({}, state.entities, { [action.payload.Instrument]: action.payload})
};
case OfferActions.UPDATE:
return {
ids: [...state.ids],
entities: Object.assign({}, state.entities, { [action.payload.Instrument]: action.payload})
}
default:
return state;
}
}
请注意,通过 object.assign(深拷贝)对临时状态进行更改,然后返回新状态。
这个问题的另一个答案有点令人困惑。它详细介绍了如何组合不同的减速器,但对我来说没有多大意义。
在你的 reducers/index.ts 你应该有一个类型:
export interface AppState {
otherReducer: OtherReducer;
offers: fromOffersReducer.OfferState;
}
在这个 index.ts 中,你应该有获取 reducer 的函数:
export function getOfferState() {
return (state$: Observable<AppState>) => state$
.select(s => s.offers);
}
export function getOtherReducer() {
return (state$ : Observable<AppState>) => state$
.select(s => s.otherReducer)
}
在我们的 offerReducer 和 otherReducer 中,我们定义了可以查询我们需要的数据的函数。这些是匿名函数,目前没有链接到任何东西,但我们稍后会链接它们(到 getReducerFunctions)。
这些函数的示例:
export function getOfferEntities() {
return (state$: Observable<OfferState>) => state$
.select(s => s.entities);
};
export function getOffer(id: string) {
return (state$: Observable<OfferState>) => state$
.select(s => s.entities[id]);
}
这没有任何作用。除非我们将它应用到我们之前制作的一些有用的数据(例如,offersReducer),然后我们像这样将两者结合起来:
import offersReducer, * as fromOffersReducer from './OffersReducer';
export function getOfferEntities() {
return compose(fromOffersReducer.getOfferEntities(), getOfferState());
}
export function getOffer(instrument:string) {
return compose(fromOffersReducer.getOffer(instrument), getOfferState());
}