Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/30.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 从ngrx/商店获取单个商品_Angular_Typescript_Redux_Store_Ngrx - Fatal编程技术网

Angular 从ngrx/商店获取单个商品

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

我编写了以下减速机来存储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;
    }
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());
 }