当调用 API 的函数在 class 中定义时,如何通过 effect call 从 redux-saga 调用 API

How to call API from redux-saga by effect call when the function to call API is defined in class

我正在尝试通过 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)
}

上面这个例子有效

但是当我尝试从 class 内部调用 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)
}

enter image description here

在幕后,redux-saga 将调用 your function with .apply,缺少 authService 对象的 this 上下文,

存储库问题中的详细信息: https://github.com/redux-saga/redux-saga/issues/27

您有 2 种方法可以解决这个问题:

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

或者您可以使用 JavaScript:

将父对象绑定到 auth.login 函数
  • yield call(authService.login.bind(authService), 'email', 'password')

我建议改用正确的效果或效果签名!

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