首页 > 解决方案 > 当调用API的函数在类中定义时,如何通过效果调用从redux-saga调用API

问题描述

我正在尝试通过 redux-saga 的效果调用来调用 API,但是何时开始调用 api 会引发错误。Cannot read property 'post' of null

真的很奇怪,因为我创建了一个简单的函数来测试我的呼叫工作示例:

function requestGetUser() {
  return axios.request({
    method: 'get',
    url: 'https://my-json-server.typicode.com/atothey/demo/user',
  })
}

export function* fetchLoginSaga(action) {
  const { data } = yield call(requestGetUser)
  yield put(login({ id: data.id, name: data.firstName }))
}

export function* watcherSaga() {
  yield takeLatest(fetchLogin.type, fetchLoginSaga)
}

并且上面的这个例子有效

但是当我尝试从效果调用内部的类调用 API 时不起作用

// Depedencies
import axios from 'axios'

export default class BaseService {
  /**
   * Default http request instane
   * @type { Axios.Instance }
   */
  instance

  /**
   * Creates an instance of BaseService.
   * @param { String } endpoint To manipulates the operations.
   * @param { String } [baseUrl= ] The base url.
   */
  constructor(endpoint, baseURL = process.env.BASE_URL) {
    this.endpoint = endpoint
    this.instance = axios.create({ baseURL })
    this.instance.interceptors.response.use(this.responseInterceptor, this.handleResponseError)
  }

  /**
   * Intercepts every response.
   * @param { Object } response The response.
   * @returns { Promise<Object> }
   */
  responseInterceptor = response => response.data

  /**
   * Intercepts every error on response.
   * @param { Object } error The respone error.
   * @returns { Promise<Object> }
   */
  handleResponseError = error => {
    const {
      response: {
        data: { message },
      },
    } = error
    return Promise.reject(new Error(message))
  }

  /**
   * Make a post request with data.
   * @param { Object } [data={}] The data to send as body.
   * @param { Object } [requestParams={}] The params to make the request.
   * @return { Promise<any> }
   */
  post = (data, { url = this.endpoint, ...rest } = {}) => {
    
    const response = this.instance.post(url, data, { ...rest })

    return response
  }

}

import BaseService from './baseService'

export class AuthService extends BaseService {
  /**
   * Initializes Auth Service.
   */
  constructor() {
    super('/auth/local')
  }

  /**
   * Logs Current user.
   * @param { String } identifier - User's Identifier
   * @param { String } password - User´s password.
   * @return { Promise<String> } jwt access token.
   */
  async login(identifier, password) {
    const user = await this.post({ password, identifier }, { url: '/auth/local' })// when I call return cant find post of null
    return user
  }
}

export default AuthService
import axios from 'axios'
import { call, takeLatest } from 'redux-saga/effects'

import { fetchLogin } from './authReducer'

import AuthService from 'api/authService'

const authService = new AuthService()

export function* fetchLoginSaga(action) {
  const response = yield call(authService.login, 'email', 'password')
  console.log({ response })// don't print
  
}

export function* watcherSaga() {
  yield takeLatest(fetchLogin.type, fetchLoginSaga)
}

在此处输入图像描述

标签: javascriptreactjsoopreduxredux-saga

解决方案


在幕后,redux-saga将调用你的函数 .apply,缺少对象的this上下文,authService

仓库 issue 中的详细信息: https ://github.com/redux-saga/redux-saga/issues/27

你有两种方法可以解决这个问题:

  1. call将签名更改为yield call([auth, 'login'], "email", "password");
  2. 您可以改用apply效果 -yield apply(auth, auth.login, ["email", "password"]);

auth.login或者您可以使用纯 JavaScript将父对象绑定到函数:

  • yield call(authService.login.bind(authService), 'email', 'password')

我建议使用正确的效果或效果签名来代替!

“context”/“fn”的文档可以在redux-saga文档中找到: https ://redux-saga.js.org/docs/api/#callcontext-fn-args


推荐阅读