Angular 从ngrx/商店获取单个商品
我编写了以下减速机来存储Angular 2应用程序中的状态项。这些项目是金融工具(如股票/货币)的报价 我的Reducer实现如下:Angular 从ngrx/商店获取单个商品,angular,typescript,redux,store,ngrx,Angular,Typescript,Redux,Store,Ngrx,我编写了以下减速机来存储Angular 2应用程序中的状态项。这些项目是金融工具(如股票/货币)的报价 我的Reducer实现如下: export const offersStore = (state = new Array<Offer>(), action:Action) => { switch(action.type){ case "Insert": return [ ...state, action.payload
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;
}
export const offersStore=(state=new Array(),action:action)=>{
开关(动作类型){
案例“插入”:
返回[
…状态,动作,有效载荷
];
案例“更新”:
返回状态.map(提供=>{
if(offer.Instrument==action.payload.Instrument)
{
返回Object.assign({},action.payload);
}
否则返回报价;
});
案例“删除”:
返回状态.filter(offer=>offer.Instrument!==action.payload)
违约:
返回状态;
}
}
我设法让插入、更新和删除都能正常工作——尽管这并不容易。我发现Redux在某种程度上改变了我多年来的编码方式
我的应用程序上有一个仪器组件/页面,显示一个特定仪器的所有可用信息,由仪器ID表示,例如“EUR/USD”(存储在payload.Instrument属性中)
我的问题是,我不知道如何有效地搜索特定的仪器并将其从商店中抢走。不仅如此,如果存储区中的仪器经常通过服务器上的websocket推送进行更新,那么我还希望我获取的仪器得到更新。因此,我真的需要在存储中搜索特定的仪器,并将其作为可观察的返回,这将根据推送到存储中的新数据继续更新视图组件
我怎样才能做到这一点呢?好的,我将尝试解释一种设置方法,并希望以您和其他人能够理解的方式进行设置 因此,如果您正在存储一个对象数组,并且需要通过某个id或键访问某一行,那么ngrx示例应用程序显示的方法是创建一个包含您的对象的对象,该对象将使用(在他们的book应用程序中)书籍的id作为属性键。可以将任何字符串设置为属性名称。假设您的状态有一个名为“entities”的属性,其值为空对象。然后可以获取数组并在“entities”对象上创建属性
export interface BooksState {
entities: { [id: string]: Book };
};
让我们从书本对象数组中的一行开始。要将此行添加到“entities”对象,请按如下方式操作
reducerState.entities[book.id] = book;
上述内容将使书籍的id成为“实体”对象的属性。如果要在控制台或调试工具中对其进行检查,则创建后可能会出现类似的情况
reducerState.entities.15: { id: 15, name: "To Kill a Mockingbird" }
ngrx示例应用程序在完整数组上运行,使用javascript数组上的reduce操作符将其添加到状态
const newBookEntities
= newBooks.reduce(
(entities: { [id: string]: Book }, book: Book) =>
{
return Object.assign(entities, { [book.id]: book });
}, {});
然后创建特殊函数以获取该状态的部分内容,这些内容可以在以后组合在一起以获取所需的特定行
export function getBooksState() {
return (state$: Observable<AppState>) => state$
.select(s => s.books);
}
export function getBookEntities() {
return (state$: Observable<BooksState>) => state$
.select(s => s.entities);
};
export function getBooks(bookIds: string[]) {
return (state$: Observable<BooksState>) => state$
.let(getBookEntities())
.map(entities => bookIds.map(id => entities[id]));
}
此函数将从右向左链接调用。首先调用getbookstate以获取reducer状态,然后调用fromBooks.getBooks并传入所需的bookid和前一个“getbookstate”的状态,并允许您映射到所需的选定状态
在您的组件中,您可以导入此函数并使用它仅获取您想要的书籍
myBooks$: Observable<Books> = this.store.let(getBooks(bookIds)));
这里有两个函数被传递到compose函数中——fromBooks.getBooks(bookIds)和getBooksState()。compose函数允许将值传递到右侧的第一个函数中,并将该函数的结果传递到左侧的函数中,依此类推。因此,在本例中,我们将获取“getbookstate”返回的函数的结果,并将其传递到函数“fromBooks.getBooks(bookIds)”返回的函数中,然后最终返回该结果
这两个函数具有可观察性。对于getbookstate()返回的函数,它将把store state observable对象作为参数,从中映射/选择(映射和选择是彼此的别名)到我们关心的存储切片,并返回新映射的observable对象。映射的可观察对象将被传递到从fromBooks.getBooks(bookIds)函数返回的函数中。此函数期望状态片是可观察的。此函数通过只提取我们关心的实体来进行新映射。这个新的可观察对象是“store.let”调用最终返回的对象
如果你需要更多的澄清,请提问,我会尽力澄清
对于减速器上调用的每个操作,都会返回新状态 根据问题中的示例代码,状态只是一个仪器列表。
没有索引,所以检查列表中是否有仪器的唯一方法是搜索整个列表 但是如果你的州是一本字典呢?此外,如果将索引列表与字典分开,会怎么样 您的状态类型如下:
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(深度复制)对临时状态进行更改,然后返回新状态
这个问题的另一个答案有点让人困惑。它详细介绍了如何组合不同的减速器,
> export default compose(storeFreeze, combineReducers) ({ oether:
> otherReducer, offers: offersReducer });
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;
}
}
export interface AppState {
otherReducer: OtherReducer;
offers: fromOffersReducer.OfferState;
}
export function getOfferState() {
return (state$: Observable<AppState>) => state$
.select(s => s.offers);
}
export function getOtherReducer() {
return (state$ : Observable<AppState>) => state$
.select(s => s.otherReducer)
}
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]);
}
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());
}