如何在 Vuex 模块中使用 RxJS

Posted

技术标签:

【中文标题】如何在 Vuex 模块中使用 RxJS【英文标题】:How to use RxJS in Vuex module 【发布时间】:2019-12-23 16:33:31 【问题描述】:

我创建了一个供 Vuex 模块使用的身份验证服务使用的 API 服务。在我的登录组件中,我使用 Vuex 模块与 API 进行通信,但调用不等待 API 响应。

API 服务:

class ApiService 
  protected readonly api = 'https://xxx.yzz:44310/api'
  private static instance: ApiService
  private headers = 
    'Content-Type': 'application/json'
  

  constructor() 
    this.init()
  

  private init() 
    Vue.use(VueAxios, axios)
    Vue.axios.defaults.baseURL = this.api
  

  public static get Instance() 
    return this.instance || (this.instance = new this())
  

  private handleError(error: any) 
    const applicationError = error.headers['Application-Error']
    return Observable.throw(modelStateErrors || 'Server error')
  

  get(path: string, params: URLSearchParams = new URLSearchParams()):     Observable<any> 
    return from(axios.get(`$path`,  params )).pipe(catchError(this.handleError))
  

  put(path: string, body: Object = ): Observable<any> 
    return from(axios.put(`$path`,     JSON.stringify(body))).pipe(catchError(this.handleError))
  

  post(path: string, body: Object = ): Observable<any> 
    return from(
      axios.post(`$path`, JSON.stringify(body), 
        headers: this.headers
      )
    ).pipe(catchError(this.handleError))
  



export const apiService = ApiService.Instance

授权服务:

class AuthService 
  private static instance: AuthService

  private constructor() 

  public static get Instance() 
    return this.instance || (this.instance = new this())
  

  public login(credentials: Credentials): Observable<any> 
    return apiService.post('/auth/login', credentials).pipe(map(result => result.data))
  


export const authService = AuthService.Instance

带有授权方式的Vuex模块:

import  Module, VuexModule, Mutation, Action  from 'vuex-module-decorators'
import  Credentials  from '@/core/models/credentials.interface'
import  authService  from '@/core/services/auth.service'
import  Usuario  from '@/core/models/usuario.interface'

@Module
export default class Auth extends VuexModule 
  count = 0
  usuario: Usuario | null = null
  isAuthenticated: boolean = false

  @Mutation
  setUsuario(usuario: Usuario) 
    this.usuario = usuario
    this.isAuthenticated = true
  

  @Action()
  public authRequest(credentials: Credentials) 
    return authService.login(credentials).subscribe(
      (usuario: Usuario) => 
        this.context.commit('setUsuario', usuario)
      ,
      (errors: any) => 
        console.log('errors', JSON.stringify(errors))
      
    )
  

在我的登录组件中,我使用 Vuex 模块如下:

  onSubmit() 
    (this.$refs.userCredentials as any).validate((valid: boolean) => 
      if (valid) 
        this.$store
          .dispatch('authRequest', this.userCredentials)
          .then(() => 
            this.$router.push('/');
          )
          .catch((err) => 
            console.error(err);
          );
       else 
        console.log('error submit!!');
        return false;
      
    );
  

我期望的结果是,当我按下登录按钮时,代码会一直等到 API 响应,然后根据结果执行后续步骤。

【问题讨论】:

Vuex 操作通常需要文字或Promise 作为返回。在Auth.authRequest() 中,尝试将返回值更改为PromisetoPromise 【参考方案1】:

authRequest 正在返回 Subscription 但要使用 .then onSubmit 逻辑在这里需要 Promise 类型。您可能想在authRequest 中使用.tap/.do 后跟.toPromise

【讨论】:

Franco,还有其他可以代替 .then 的吗?【参考方案2】:

是的,您在操作中返回订阅,而您不想这样做。在您的操作中将 .subscribe 替换为 .pipe(shareReplay()) 。 Observable 实现了 PromiseLike,所以你可能会很好。如果这仍然不起作用,则必须在操作中的 return 语句末尾调用 .toPromise() 。一个 vuex-rxjs 库将是一件美好的事情,我希望我有时间去做。希望其他人很快就会这样做:)

【讨论】:

以上是关于如何在 Vuex 模块中使用 RxJS的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Vuex 模块 Actions 中使用 vue-router?

如何在 Vuex 4 和 TypeScript 中使用其他存储模块 getter/actions/mutations

Vue 3 - 如何使用 vuex 模块?

如何在RXJS 6.3.3中使用ForkJoin导入Observer?

Vuex |如何在模块操作中提交全局突变?

如何在带有 vuetify 和 vuex 的 Vuejs 项目中使用 Jest?节点模块和 Vuetify 问题