这是一个具体问题,没有可以在网上轻松找到合适答案的问题。
/ *背景故事-可跳过* /
我最近创建了一个新项目,旨在遵循Redux Patterns,同时还使用Google Firestore作为我选择的数据存储。
因为这是一个新应用程序,它相对来说是空的-但是,我认为首先通过身份验证将信息添加到数据存储中是合适的。
过去,我曾使用一项服务登录并处理身份验证。但是,这次我正在使用NgRx。
我已经设法正确设置商店,并且在使用选择器,操作和简化器时,它可以按预期工作。但是-问题出在需要效果时,例如通过Google Firestore评估信息时。
/ *背景故事结束* /
问题
问题是,尝试登录时会触发适当的身份验证操作,但是存储被冻结,并且在遇到致命错误后不会更新。
这样,我们将永远不会收到用户信息,并且下图中显示的错误使商店停止运转。
上面的错误是在调度操作以登录后发生的。触发登录事件,并从服务器收到状态为200的响应。它在“网络”选项卡中返回所需的信息。纯粹在事物的存储方面,事物会失败。
我想知道为什么。
The Project
我对该项目具有以下设置。
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
}),
],
概述
尝试过的内容/有用的信息
如果我从登录成功中删除了道具并且没有通过用户,则代码会运行-但显然这是没有用的,因为我无法将所需的信息实际传递回商店。
我将其重构如下:
对于状态-
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
}
});