Если у меня есть такая модель:

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 в 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
  }
1
noririco 8 Окт 2018 в 10:40

2 ответа

Лучший ответ

Я бы рекомендовал использовать следующую структуру для подобных случаев

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

Таким образом вы преодолеете свою проблему.

Примечание: Я предполагаю, что в какой-то момент прямо сейчас у вас есть некоторые неопределенные связанные ошибки, которые связаны с доступом к неинициализированным полям в магазине, но даже сейчас, если параметр optional является каким-то объектом, вы все равно будете получать ошибки ( при доступе к некоторым свойствам объекта). Мой совет - создать некоторую логику фильтрации в ваших потоках (найдите оператор фильтра rxjs) или используйте оператор ? в ваших шаблонах.

Редактировать

Хорошо, я думаю, теперь у меня есть твоя проблема.

Во-первых: вы должны добавить runGuardsAndResolvers в конфигурацию пути, чтобы преобразователь запускался каждый раз, когда вы меняете маршрут, который находится слева от пути, на котором находится преобразователь или текущий (например, если вы измените параметры но оставайся на том же пути)

Во-вторых: добавьте действие new MovieReset(), цель которого - сбросить состояние хранилища (другими словами, чтобы очистить его)

После того, как вы создадите такое действие, один из способов его использования - отправить его в ловушку ngDestroy в MovieDetailsComponent, которая сбрасывает фильм, который будет создавать, так что преобразователь будет возвращать новый фильм каждый раз, когда он triggerd .

Другой способ почти такой же, но вместо того, чтобы использовать его в хуке onDestroy, вы можете сбросить хранилище в самом преобразователе и через switchMap (после отправки действия сброса), чтобы вернуть новое значение который сохраняется в магазине.

2
Християн Христов 8 Окт 2018 в 08:57

Можете ли вы опубликовать Reducer, который вы используете для действия MovieRequested?

В редукторе вы можете вернуть свое предыдущее состояние, дополненное новыми данными для действия 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
   }],
   ...
}
0
Tac 8 Окт 2018 в 09:12