NGRX Select:选择如何与内部对象一起使用?

NGRX Select: How is the selection working with an inner object?

我是 NGRX 的新手并尝试获得 运行 一个简单的 NGRX 示例。我有一个名为 LoginState 的接口,它是我商店中的对象。 LoginState 包含一个 IUser 类型的用户对象。如果我 select 在我的组件中的这个对象上,如果用户对象发生变化,我不会返回 IUser(我的效果似乎工作正常,因为如果我只是在商店上订阅,我会返回所有状态更改)。

这是我的配置:

app.module.ts

imports: [
    ...
    StoreModule.forRoot({loginState: loginReducer})
]

login.actions.ts

export const userLoginRequest = createAction('[Login] user login request');
export const userLoginFacebookSuccess = createAction('[Login] user login facebook success', props<{socialUser: SocialUser}>());
export const userLoginSuccess = createAction('[Login] user login success', props<{user: IUser}>());

login.reducer.ts

export interface LoginState {
    request: boolean;
    socialUser?: SocialUser;
    user?: IUser;
}

export const initialState: LoginState = {
    request: false
};

const reducer = createReducer(initialState,
    on(userLoginRequest, (status, action) => ({
        ...status,
        request: true
     })),
    on(userLoginFacebookSuccess, (status, action) => ({
        ...status,
        socialUser: action.socialUser
    })),
    on(userLoginSuccess, (status, action) => ({
        ...status,
        user: action.user
    }))
);

export function loginReducer(sta: LoginState, action: Action): LoginState {
    return reducer(sta, action);
}

login.effects.ts

import { userLoginRequest, userLoginSuccess, userLoginFacebookSuccess } from './login.action';

@Injectable()
export class LoginEffects {

loginFacebook$ = createEffect(() => this.actions$.pipe(
    ofType(userLoginRequest),
    switchMap(() =>
        this.authService.loginFacebook()
            .pipe(
                 map((socialUser) => {
                     this.tokenService.saveToken(socialUser.authToken);
                     return userLoginFacebookSuccess({socialUser});
                 })
            )
        )
     )
 );

loadUser$ = createEffect(() => this.actions$.pipe(
    ofType(userLoginFacebookSuccess),
    switchMap((act) =>
        this.userService.getUser(act.socialUser)
            .pipe(
                map((usr) => userLoginSuccess({user: usr}))
            )
        )
    )
);


constructor(
  private actions$: Actions,
  private authService: AuthWrapperService,
  private tokenService: TokenStorageService,
  private userService: UserService
) {}

}

Login.component.ts

export class LoginComponent implements OnInit {

localUser: IUser;

constructor(
          private router: Router,
          private store: Store<LoginState>
){}

signInWithFB(): void {
    this.store.dispatch(userLoginRequest());
}

ngOnInit() {
    this.store.select(selectUser).subscribe( (user) => {
    console.log(JSON.stringify(user, undefined, 2));
}
);
}
}

const loginState = (state: LoginState) => state;

export const selectUser = createSelector(
  loginState,
  (state: LoginState) => state.user
);

非常感谢您的帮助!

干杯,

您拥有的代码很好,您需要记住 ngrx 会立即选择数据,即使您没有。

因此,当 this.store.select(selectUser) 在使用加载之前第一次执行时,它将 return 未定义,这是预期的。

处理完 userLoginSuccess 后,我们在商店中有一个用户,选择器将发出所需用户的第二个值。

如果您希望始终获得用户,则可以过滤流中的发射。另请注意,您所在的州在 loginState 以下,因此您需要使用 createFeatureSelector.


const loginStateFeature = createFeatureSelector<LoginState>('loginState');

export const selectUser = createSelector(
  loginStateFeature,
  (state: LoginState) => state.user
);


ngOnInit() {
  this.store.select(selectUser).pipe(
    filter(user => !!user), // skipping falsy emits.
  ).subscribe((user) => {
    console.log(JSON.stringify(user, undefined, 2));
  });
}