Angular RxJs订户是isn';t在存储更改后立即更新
项目: 我正在Angular中使用NgRx和RxJs构建一个登录组件 当前设置 在login.component.ts文件的构造函数中,我订阅了“login”状态 单击UI中的“登录”按钮后,我将在以下流程中发送一个操作: GetUser Action>GetUser Effect HTTP request>Success=GetUserSuccess Action>GetUserSuccess Reducer将有效负载(jwt令牌)添加到存储中,并将“isLoggedIn”属性更改为true 如果失败,GetUserFailure操作将从效果中调度,GetUserFailure Reducer除了向“errorMsg”属性下的存储添加错误消息之外,不会添加任何内容 所需的下一步 在login.component.ts中,由于我已经订阅了登录状态,我希望检查'isLoggedIn'是真是假。如果为true,Angular RxJs订户是isn';t在存储更改后立即更新,angular,rxjs,ngrx-store,Angular,Rxjs,Ngrx Store,项目: 我正在Angular中使用NgRx和RxJs构建一个登录组件 当前设置 在login.component.ts文件的构造函数中,我订阅了“login”状态 单击UI中的“登录”按钮后,我将在以下流程中发送一个操作: GetUser Action>GetUser Effect HTTP request>Success=GetUserSuccess Action>GetUserSuccess Reducer将有效负载(jwt令牌)添加到存储中,并将“isLoggedIn”属性更改为true
this.router.navigateByUrl('/dashboard')代码>否则,从存储中获取“errorMsg”,并将其作为字符串在页面上输出
问题
我在一个从登录按钮触发的函数中调度一个操作,但我也希望在检查完商店后导航。如果我单击按钮一次,我可以得到一个控制台日志,其中说明“isLoggedIn”为false(就像我单击按钮时一样)。但是,如果我再次单击该按钮,它将变为true
如何确保login.component.ts文件正在主动监视存储,并在该值更改为true后路由到“dashboard”?我假设下面的代码可以做到这一点,但显然不行
代码
内部构造:
this.store.subscribe(state => (this.loginState$ = state));
在单击Login按钮时触发的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$);
}
总之
我如何等待商店属性的更改,然后基于该属性进行路由而不使用设置间隔之类的东西?Jamie!谢谢你提出这么详细的问题!对任务有一个完整的描述总是好的
为什么不能立即看到更改?
由于NgRx代码的异步性质,您无法立即看到变量中的更改。简短描述-当函数未完成时,事件仍在队列中。如果将其包装在setTimeout(()=>console.log(this.loginState$)中,
如何解决您的案件?
我对这个问题的建议是创建一个带有登录状态的Observable并订阅它。之后,检查是否有用户登录或发生错误。
在本例中,您的代码如下所示:
类日志组件{
isLoggedIn$:可观察;
构造函数(私有存储:存储){
this.isLoggedIn$=this.store.select(state=>state.isLoggedIn);
}
onSubmit(){
const loginCredentials=this.loginForm;
this.store.dispatch(new GetUser(loginCredentials.value));
//首先是防止多次调用。它可能会触发两到三次。在您的代码中,解决方案可能会有所不同
this.isLoggedIn$.pipe(first()).subscribe(isUserLoggedId=>{
if(isUserLoggedIn){
这个。重定向到仪表板();
}否则{
这是一条消息();
}
}
}
建议
使用NGRX,以反应式编程方式思考始终是一个不错的选择。应用程序中的任何数据都是可观察的,并且每个操作都是异步的。它可以在未来节省您几个小时的生命
p.S.以更简单的方式使用此异步可观察数据
我希望我能帮助你!致以最良好的祝愿。感谢那些回答/帮助你的人
修复程序
// 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或函数中的存储
我只是将订阅移动到login函数中,将函数本身扩展为在本地使用“loginState$”(就像我之前所做的那样),但随后根据该状态中的值进行路由
据我所知,因为我订阅了构造函数之外的状态,所以它会根据需要立即更新状态
另外,通过将订阅分配给常量变量,我可以在Ngondestry lifecycle hook中取消订阅,以防止内存泄漏。您应该创建一个选择器,用于选择isLoggedIn属性。查看文档: