Действия запускаются, но магазин зависает при использовании эффектов с откликом - PullRequest
0 голосов
/ 21 марта 2020

Это конкретный c вопрос без подходящего ответа, который легко найти в Интернете.

/ * Предыстория - SKIPPABLE * /

Я создал новый проект недавно, с намерением следовать шаблонам Redux к письму, а также использовать Google Firestore в качестве моего выбранного хранилища данных.

Поскольку это новое приложение, оно относительно пустое - однако я посчитал целесообразным сначала настроить добавление информации в хранилище данных при аутентификации.

В прошлом я использовал службу войти и обработать аутентификацию. Тем не менее, на этот раз я использую NgRx.

Мне удалось правильно настроить хранилище, и оно работает как положено при использовании селекторов, действий и редукторов. Однако проблема заключается в том, когда требуются эффекты, например, при оценке информации через Google Firestore.

/ * Конец предыстории * /

Проблема

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

Таким образом, мы никогда не получаем информацию о пользователях, и ошибка, показанная на рисунке ниже, останавливает хранилище в его треках.

enter image description here

Приведенная выше ошибка возникает после отправки действия для входа в систему. Событие входа в систему инициировано, и ответ получен с сервера со статусом 200. Он возвращает необходимую информацию на вкладке сети. Это просто на стороне магазина вещей, что вещи терпят неудачу.

Я хочу знать, почему.

Проект

У меня есть следующие настройки для проекта.

auth.actions.ts

export const getAuthState = createAction('[Auth] Get Auth State');

export const login = createAction('[Auth] Login', props<{ credentials: Credentials }>());
export const loginSuccess = createAction('[Auth] Login Successful', props<{ user: UserCredential }>());
export const loginFailure = createAction('[Auth] Login Failed', props<{ error: any }>());
export const loginFinalize = createAction('[Auth] Login Finalized');

auth.reducer.ts

export interface AuthState {
  authenticated: boolean;
  authenticationRequestSent: boolean;
  authenticationResponseReceived: boolean;
  error: string;
}

const initialState: AuthState = {
  authenticated: false,
  authenticationRequestSent: false,
  authenticationResponseReceived: false,
  error: null
};

const authReducer = createReducer(initialState,
  on(authActions.getAuthState, state => {
    return {
      ...state,
    };
  }),
  on(authActions.login, state => {
    return {
      ...state,
      authenticationRequestSent: true
    }
  }),
  on(authActions.loginSuccess, state => {
    return {
      ...state,
      authenticationResponseReceived: true
    }
  }),
  on(authActions.loginFinalize, state => {
    return {
      ...state,
      authenticationRequestSent: false,
      authenticationResponseReceived: false
    }
  })
);

export function AuthReducer(state = initialState, action: Action) {
  return authReducer(state, action);
}

auth.effects.ts

@Injectable()
export class AuthEffects {
  login$: Observable<Action> = createEffect<any, any, any, any>(() =>
    this.actions$.pipe(
      ofType(authActions.login),
      switchMap(action =>
        this.authService.logIn(action.credentials).pipe(
          switchMap((userResponse: UserCredential) => from([
            authActions.loginSuccess({user: userResponse}),
            authActions.loginFinalize()
          ])),
          catchError(error => from([
            authActions.loginFailure({error}),
            authActions.loginFinalize()
          ]))
        )
      )
    )
  );

  constructor(
    private actions$: Actions,
    private authService: AuthService
  ) {
  }
}

auth.service.ts

constructor(private firebaseAuth: AngularFireAuth
  ) {
  }

  logIn(credentials: Credentials) {
    const login = new BehaviorSubject(null);
    const login$ = login.asObservable();

    this.firebaseAuth.auth.signInWithEmailAndPassword(credentials.email, credentials.password)
      .then(response => {
        login.next(response);
      }, errorData => {
        login.error(errorData);
      });
    return login$;
  }

app.module.ts

imports: [
    BrowserModule,
    AppRoutingModule,
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFirestoreModule, // firestore
    AngularFireAuthModule, // auth
    AngularFireStorageModule, // storage
    StoreModule.forRoot(reducers),
    EffectsModule.forRoot([AuthEffects]),
    StoreDevtoolsModule.instrument({
      maxAge: 25, // Retains last 25 states
      logOnly: environment.production, // Restrict extension to log-only mode
    }),
  ],

Обзор

  1. Действие для входа отправляется по нажатию кнопки
  2. Действие входа регистрируется в состоянии и отправляет свой запрос на сервер
  3. Получен правильный ответ с информацией пользователя
  4. Успешный вход в систему и завершаются действия входа в систему, однако они фактически не изменяют состояние хранилища, поскольку они сталкиваются с фатальной ошибкой, которая эффективно «замораживает» хранилище.
  5. Таким образом, наш логин, хотя и успешный, никогда не регистрируется как таковой, и пользователь не обновляется.

Что пробовали / Полезная информация

Если я Извлеките реквизиты из входа в систему успешно и не передайте пользователя, код запускается - но, очевидно, это бесполезно, поскольку я не могу фактически передать требуемую информацию обратно в магазин.

1 Ответ

0 голосов
/ 21 марта 2020

Я бы изменил это следующим образом:

Для состояния -

export interface AuthState {
  authenticated: boolean;
  error: string;
  user: UserCredential;
}

const initialState: AuthState = {
  authenticated: false,
  error: null,
  user: null
};

Для эффекта -

login$: Observable<Action> = createEffect<any, any, any, any>(() =>
    this.actions$.pipe(
      ofType(authActions.login),
      switchMap(action =>
        this.authService.logIn(action.credentials).pipe(
          map((userResponse: UserCredential) => authActions.loginSuccess({user: userResponse})),
          catchError(error => authActions.loginFailure({error}))
        )
      )
    )

Для редуктора -

on(authActions.loginSuccess, (state, { user })  => {
  return {
    ...state,
    authenticated: true,
    user: user,
    error: null
  }
});

on(authActions.loginError, (state, { error })  => {
  return {
    ...state,
    authenticated: false,
    user: null,
    error: error
  }
});
...