我编写了以下缩减器来将状态项存储在我的 Angular 2 应用程序中。这些项目是金融工具(例如股票/货币)的报价。
我的 Reducer 实现如下:
export const offersStore = (state = new Array<Offer>(), action:Action) => {
switch(action.type){
case "Insert":
return [
...state, action.payload
];
case "Update":
return state.map(offer => {
if(offer.Instrument === action.payload.Instrument)
{
return Object.assign({}, action.payload);
}
else return offer;
});
case "Delete":
return state.filter(offer => offer.Instrument !== action.payload )
default:
return state;
}
我设法让插入、更新和删除正常工作——尽管这并不容易。我发现 Redux 是一种范式转变,与我多年来的编码方式不同。
我的应用程序上有一个仪器组件/页面 - 它显示了一个特定仪器的所有可用信息,由 InstrumentId 指示,例如“EUR/USD”(存储在 payload.Instrument 属性中)。
我的问题是,我不确定如何有效地搜索特定乐器并将其从商店中取出。不仅如此,我还希望在商店中的乐器更新时更新我获取的乐器,因为它们经常通过服务器的 websocket 推送进行更新。所以我真的需要在商店中搜索特定的仪器,并将其作为 Observable 返回,这将根据推送到商店的新数据继续更新 View 组件。
我怎样才能做到这一点?
最佳答案
对于在 reducer 上调用的每个操作,都会返回新状态。
从问题中的示例代码来看,状态只是一个工具列表。
没有索引,所以检查仪器是否在列表中的唯一方法是搜索整个列表。
但是如果你的状态是一本字典呢?此外,如果您将索引列表与字典分开会怎么样?
你的状态类型是这样的:
export interface OfferState {
ids: string[];
entities: { [id: string]: IOffer };
};
任何时候执行一个 Action ,都会返回新的状态。这是 Redux 中的一个重要概念,因为状态永远不能直接改变。当你编写你的 reducer 时,你实际上最好严格执行这一点:(假设你有你“提供 reducer ”和另一个 reducer ,你将它们组合成一个组合:
> export default compose(storeFreeze, combineReducers) ({ oether:
> otherReducer, offers: offersReducer });
在 Redux 中很容易出错——但是如果你试图直接改变状态,使用 storeFreeze 会抛出一个错误。关键是 Action 会改变状态,并产生新的状态。它们不会更改现有状态 - 它让我们可以撤消/重做...等。
使用上面的示例,我会将其用作我的 Offer 的 reducer:
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(深拷贝)对临时状态进行更改,然后返回新状态。
这个问题的另一个答案有点令人困惑。它详细介绍了如何组合不同的 reducer ,但对我来说意义不大。
在你的 reducers/index.ts 中你应该有一个类型:
export interface AppState {
otherReducer: OtherReducer;
offers: fromOffersReducer.OfferState;
}
在这个 index.ts 中,你应该有获取 reducers 的函数:
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]);
}
这什么都不做。除非我们将它应用到一些我们简化的有用数据(例如 offersRedeucer),然后我们像这样将两者结合起来:
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());
}
关于angular - 从 ngrx/store 获取单个项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38957510/