ngrx建模和状态

时间:2018-10-08 07:40:54

标签: angular api ngrx

如果我有这样的模型:

export interface User {
    id: string;
    email: string;
    someOptional?: string;
}

并从api中获得2种结构:

{
  id: 1,
  email: x@l.com
}

{
  id: 1,
  email: x@l.com,
  someOptional: "something"
}

商店目前具有第一种结构。 现在获取第二个结构将导致商店拉出第一个结构,而不是新的“扩展版本”,因为它已经(当然)已经有了它。

我该如何克服? 我需要创建一个新状态来保存扩展版本吗?

@PierreDuc发表评论: 我这样解决我的路线

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): 
 Observable<Movie> {

        const movieId = route.params['id'];
        //WORKFLOW: ((6))
        return this.store
          .pipe(
            select(selectMovieById(movieId)),
            tap(movie => {
              if (!movie) {
                this.store.dispatch(new MovieRequested({movieId}));
              }
            }),
            filter(movie => !!movie),
            first()
          )



    }

,但selectMovieById(movieId)从商店返回的电影的属性比MovieRequested({movieId})少 因此,当我从/ movies移至电影/ 123时,我不会使用MovieRequested({movieId}) 但是如果我刷新电影/ 123,我将获得正确的数据,并且“电影”状态仅包含1个项目。

我应该将此扩展版本存储为“ currentMovie”状态吗?

@ХристиянХристов进行评论:

export const moviesRoutes: Routes = [
  {
      path: "",
      component: HomeComponent

  },
  {
      path: ':id',
      component: MovieDetailsComponent,
      resolve: {
          movie: MovieResolver
      }
  }
];

解决方案:感谢@ХристиянХристов 在解析器中添加

this.store.dispatch(new MovieClear());

在开始时会起作用。对于那些想知道MovieClear减速器的人

case MoviesActionTypes.MovieClear:

  return {
    ...state,
    currentMovie: undefined
  }

2 个答案:

答案 0 :(得分:2)

对于类似的情况,我建议采用以下结构

let initialState = {
  id: undefined,
  email: undefined,
  optional: undefined
}

这样,您将克服问题。

注意: 我假设现在您正在遇到一些未定义的相关错误,这是由于访问存储中的未初始化字段而引起的,但是即使现在optional参数是某种对象,您仍然会得到错误(访问某些对象属性时)。我的建议是在流中进行一些过滤逻辑(查找rxjs过滤器运算符),或在模板中使用?运算符。

编辑

好的,我想我现在遇到了您的问题。

首先:您必须在路径配置中添加runGuardsAndResolvers,以便每次更改路由时都会触发解析器,该路径位于解析器或当前路径的左侧(例如,如果您选择更改参数,但保持相同的路径

第二:添加一个new MovieReset()动作,目的是重置存储状态(换句话说,将其清除)

创建此类动作后,使用该动作的一种方法是将其分配到ngDestroy的{​​{1}}钩子中,这将重置制作的电影,以便解析器每次返回新电影。时间被触发。

另一种方法几乎相同,但是可以在MovieDetailsComponent钩子中使用它,而可以在解析器本身中重置存储,并通过onDestroy(在分派reset操作之后)返回存储在商店中的新值。

答案 1 :(得分:0)

您可以发布用于“ MovieRequested”操作的Reducer吗?

在Reducer中,您可以返回先前状态,其中扩展了带有“ MovieLoaded”操作的新数据的扩展状态(或者您如何调用获取新电影数据的操作)。 这可能看起来像这样:

switch(action.type) {
   case MovieActionTypes.MOVIE_LOADED: {
      return {
         ...state,
         movies: action.payload
      }
   }

该代码中的“ ...状态”被截断,告诉商店使用您以前的状态并将其扩展到下一部分(电影)。这样,您将获得如下所示的状态:

state = {
   movies: [
      {
         id: 1,
         email: x@l.com
      },
      {
         id: 2,
         email: x@2.com
      }
   ],
   ...

如果这是您想要的(恕我直言,这是商店的目的,因此您保留了会话中请求的所有物品),则必须调整状态以使其可以容纳多部电影:

export interface State {
   isLoading: boolean;
   error: any;
   movies: Array<Movie>;
   ...
}

export const initialMovieState: State = {
   isLoading: false,
   error: "",
   movies: [{
      id: 1,
      email: x@1.com
   }],
   ...
}