typescript Angular 2/4 - 在前端存储当前用户对象的详细信息(而不是向后端发出连续的 HTTP 请求)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46593340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:56:43  来源:igfitidea点击:

Angular 2/4 - Storing the Current User Object Details in front-end (rather than making continuous HTTP requests to back-end)

angulartypescript

提问by ToDo

I would like an efficient way to store (and update) the current user details in the frontend, rather than making new HTTP GET requests to the backend whenever a new component is loaded.

我想要一种在前端存储(和更新)当前用户详细信息的有效方法,而不是在加载新组件时向后端发出新的 HTTP GET 请求。

I have added a UserService class which sets/updates a currentUser object when a method in the class is called.

我添加了一个 UserService 类,它在调用类中的方法时设置/更新 currentUser 对象。

import { Http, Response } from '@angular/http';
import { Injectable } from '@angular/core';

@Injectable()
export class UserService {

    public currentUser: any;

  constructor(private http: Http) { }

  updateCurrentUser() {
    this.http.get('api/login/currentUser').subscribe(data => {
        this.currentUser = data;
    });
  }

}

I have found this method to cause a race condition problems. For example, an error occurs if the currentUser.usernameis requested in the profile component but the service class hasn't completed the request yet.

我发现这种方法会导致竞争条件问题。例如,如果currentUser.username在配置文件组件中请求了 ,但服务类尚未完成请求,则会发生错误。

I've also tried checking if the currentUseris undefined and then calling the updateCurrentUser()but it doesn't seem to work.

我也试过检查 是否currentUser未定义,然后调用 ,updateCurrentUser()但它似乎不起作用。

if(this.userService.currentUser === undefined){
    this.userService.updateCurrentUser();
} 


Update:The error message shown in the browser console enter image description here


更新:浏览器控制台中显示的错误消息 在此处输入图片说明


Update on HTML used:
I am using data binding to display the username (calling it directly from the UserService class). E.g.


使用的 HTML 更新:
我使用数据绑定来显示用户名(直接从 UserService 类调用它)。例如

<span class="username-block">{{userService.currentUser.username}}</span>

I have also tried assigning the currentUser object to a variable within the component that I trying to display the username but it has the same result.

我还尝试将 currentUser 对象分配给我尝试显示用户名的组件中的一个变量,但结果相同。


I would appreciate any help/feedback.


我将不胜感激任何帮助/反馈。

回答by Richard Matsen

You can try the Elvis/existential operator (I think that's the right name) in the html. The question mark after currentUser says don't bother trying to evaluate username if currentUser is undefined.

您可以在 html 中尝试 Elvis/existential 运算符(我认为这是正确的名称)。currentUser 后面的问号表示如果 currentUser 未定义,请不要费心尝试评估用户名。

Assuming your async code will eventually fill it in, the page should then display it.

假设您的异步代码最终会填充它,那么页面应该会显示它。

<span class="username-block">{{userService.currentUser?.username}}</span>

Edit

编辑

I just noticed you are outputting userService.currentUser.username. You may want to return an observable from the service to the component so that the data is reactive. Something like,

我刚刚注意到你正在输出userService.currentUser.username。您可能希望从服务返回一个 observable 到组件,以便数据是反应式的。就像是,

updateCurrentUser() {
    return this.http.get('api/login/currentUser')
      .catch(error => this.handleError(error, 'currentUser'));
}

Then in the component,

然后在组件中,

private currentUser;

ngOnInit() {
  this.userService.updateCurrentUser()
    .take(1)
    .subscribe(data => { this.currentUser = data });
}

and the html now refers to the local component copy, initially undefined but eventually filled in by the subscription. Note, take(1)is to close the subscription and avoid memory leaks.

并且 html 现在指的是本地组件副本,最初未定义但最终由订阅填充。注意,take(1)是关闭订阅,避免内存泄漏。

    <span class="username-block">{{currentUser?.username}}</span>

Edit #2

编辑 #2

Apologies, your question asks about avoiding multiple HTTP calls.
In that case the service code should be

抱歉,您的问题是关于避免多次 HTTP 调用。
在这种情况下,服务代码应该是

export class UserService {

  private currentUser: any; // private because only want to access through getCurrentUser()

  constructor(private http: Http) { }

  getCurrentUser() {
    return this.currentUser
      ? Observable.of(this.currentUser) // wrap cached value for consistent return value
      : this.http.get('api/login/currentUser')
          .do(data => { this.currentUser = data }) // cache it for next call
          .catch(error => this.handleError(error, 'currentUser'));
  }

回答by DeborahK

Are you using routing? If so, you could set up a route resolver on your first route that needs the user data. The resolver then always waits to display the view until the resolver data is retrieved.

你在使用路由吗?如果是这样,您可以在需要用户数据的第一条路由上设置路由解析器。然后,解析器始终等待显示视图,直到检索到解析器数据。

For example, here is one of my route resolvers. Notice that it calls a service to retrieve the data.

例如,这是我的路由解析器之一。请注意,它调用服务来检索数据。

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

import { Observable } from 'rxjs/Observable';

import { IMovie } from './movie';
import { MovieService } from './movie.service';

@Injectable()
export class MovieResolver implements Resolve<IMovie> {

    constructor(private movieService: MovieService) { }

    resolve(route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot): Observable<IMovie> {
        const id = route.paramMap.get('id');
        return this.movieService.getMovie(+id);
    }
}

The resolver is then added to the appropriate route, something like this:

然后将解析器添加到适当的路由中,如下所示:

  {
    path: ':id',
    resolve: { movie: MovieResolver },
    component: MovieDetailComponent
  },

That route won't be displayed then until the data is retrieved.

在检索数据之前,不会显示该路线。