项目:
我正在使用NgRx和RxJs在Angular中构建一个登录组件。
当前设置
在我的login.component.ts文件的构造函数中,我订阅了“登录”状态。
在用户界面中单击“登录”按钮后,我将按照以下流程发送操作:
GetUser操作> GetUser效果HTTP请求>成功= GetUserSuccess操作> GetUserSuccess Reducer将有效负载(jwt令牌)添加到存储中,并将'isLoggedIn'属性更改为true。
如果失败,则从效果中分派GetUserFailure Action,GetUserFailure Reducer不会将错误消息添加到“ errorMsg”属性下的商店中。
所需的下一步
在login.component.ts中,因为我已订阅登录状态,所以我想检查一下'isLoggedIn'是true还是false。如果为true,则this.router.navigateByUrl('/dashboard');
,否则,从商店中获取“ errorMsg”,并将其作为字符串吐到页面上。
问题
我正在从登录按钮触发的函数中调度操作,但是我还想在检查商店后导航。如果单击一次按钮,我将获得一个控制台日志,指出“ isLoggedIn”为false(就像单击按钮时一样)。但是,如果我再次单击该按钮,它将变为true。
如何确保login.component.ts文件正在主动监视商店,并且在该值更改为true时路由到“仪表板”?我以为下面的代码可以做到,但显然不能。
代码
内部构造函数:
this.store.subscribe(state => (this.loginState$ = state));
在单击“登录”按钮时触发的loginHandler函数内部:
loginHandler() {
const loginCredentials = this.loginForm;
this.store.dispatch(new GetUser(loginCredentials.value));
// this.loginState$.isLoggedIn should be true, but it's false
// (presumably because it's checking before the HTTP request and reducer has fired)
console.warn(this.loginState$);
}
摘要
我如何等待看到商店属性更改,然后基于此路由而不使用诸如设置间隔之类的东西?
答案 0 :(得分:1)
杰米!谢谢您这么详细的问题!完整地描述任务总是很好的。
为什么您不能立即看到更改?
由于NgRx代码的异步特性,您无法立即看到变量中的更改。简短说明-事件尚未完成,事件仍在队列中。如果将其包装在setTimeout(() => console.log(this.loginState$))
中,它将发生变化。
如何解决您的情况?
我对这个问题的建议是创建一个具有登录状态的Observable并订阅它。之后,检查用户是否已登录或发生了一些错误。 在这种情况下,您的代码将如下所示:
class LogginComponent {
isLoggedIn$: Observable<boolean>;
constructor(private store: Store<{isLoggedIn: boolean}>) {
this.isLoggedIn$ = this.store.select(state => state.isLoggedIn);
}
onSubmit() {
const loginCredentials = this.loginForm;
this.store.dispatch(new GetUser(loginCredentials.value));
// First is here to prevent multiple calls. It could trigger two or three times. In your code solution could be different
this.isLoggedIn$.pipe(first()).subscribe(isUserLoggedId => {
if(isUserLoggedIn) {
this.redirectToDashboard();
} else {
this.showErrorMessage();
}
}
}
建议
使用NGRX,以反应式编程方式思考始终是一个不错的选择。应用程序中的任何数据都是可观察的,每个动作都是异步的。将来可以节省数小时的生命。
PS 。要以更简单的方式处理此异步可观察数据,可以使用selectors。
希望我能对您有所帮助!最好的问候。
答案 1 :(得分:0)
感谢那些回答/帮助过的人!
修复
// Subscribe to the store, check if logged in, if so route, else get error message
this.userStateSubscription = this.store.subscribe(state => {
this.loginState$ = state;
if (this.loginState$.login.isLoggedIn) {
this.router.navigateByUrl('/dashboard');
} else {
this.errorMsg = this.loginState$.login.error;
}
简而言之
尽管我是在构造函数中订阅商店的,而不是在OnInit或函数中订阅的。
我只是将订阅移到了登录函数中,将函数本身扩展为在本地使用“ loginState $”(就像我之前所做的那样),但是随后根据该状态下的值进行了路由。
据我了解,由于我已订阅构造函数的OUTSIDE状态,因此它会根据需要立即更新状态。
此外,通过将订阅分配给const变量,我随后可以在NgOnDestroy生命周期挂钩中取消订阅,以防止内存泄漏。