Reactjs 如何在React和redux应用程序中使用redux pack将承诺链接到API调用的返回?

Reactjs 如何在React和redux应用程序中使用redux pack将承诺链接到API调用的返回?,reactjs,promise,react-redux,Reactjs,Promise,React Redux,我得到了一个错误。那么()在尝试编写React应用程序testw/jest/enzyme时不是一个函数。我不认为测试代码是问题所在,但作为参考,我遵循这一点 下面是引发错误的代码: return store.dispatch(actions.fetchFiles()).then(() => { expect(store.getActions()).toEqual(expectedActions) }); 我的客户的代码库使用redux pack和一些我不熟悉的约定,我很难理解实际承诺

我得到了一个错误
。那么()在尝试编写React应用程序testw/jest/enzyme时不是一个函数。我不认为测试代码是问题所在,但作为参考,我遵循这一点

下面是引发错误的代码:

return store.dispatch(actions.fetchFiles()).then(() => {
  expect(store.getActions()).toEqual(expectedActions)
});
我的客户的代码库使用redux pack和一些我不熟悉的约定,我很难理解实际承诺在哪里执行,因此在从我的测试代码调用“then”函数时如何链接它,如上面发布的redux示例链接所示

我试着做了一些调试日志记录和一些语法变体,例如,我尝试调用。然后直接调用
actions.fetchFiles()
,因为我觉得实际上是调用返回了承诺,但它不起作用。我在所有这些代码中都有点迷失了方向,并质疑承诺到底在哪里执行/返回

该守则的基本结构如下:

一个已连接的容器组件,它从API获取文件列表,然后进行分派

实际页面运行良好,但我的测试尝试(如上面提到的Redux文章)失败了

以下是我认为相关的代码块:

容器组件

componentDidMount() {
    const { actions } = this.props;
    actions.fetchUpload();
  }

const mapStateToProps = state => ({
  ...state.upload,
});

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators({ 
    ...uploadActions,
  }, dispatch),
});

export default connect(mapStateToProps, mapDispatchToProps)(UploadContainer);
actions.js

import api from '../../core/api';

export const FETCH_FILES = 'upload/fetch-files';

const actions = {
  fetchFiles: () => ({
    type: FETCH_FILES,
    promise: api.upload.getFiles()
  })
};

actions.fetchUpload = () => (dispatch) => {
  dispatch(actions.fetchFiles());
};

export default actions;
reducer.js

import { handle } from 'redux-pack';
import { FETCH_FILES } from './actions';

const initialState = {
  files: []
};

export default (state = initialState, action) => {
  switch (action.type) {
    case FETCH_FILES:
      return handle(state, action, { // this is redux-pack syntax
        success: (s, a) => ({ ...s, files: a.payload.files })
      });

    default:
      return state;
  }
};
upload.js(api.upload.getFiles)

api.js-使用Axios

import Axios from 'axios';
import { SubmissionError } from 'redux-form';
import queryString from 'query-string';
import upload from './upload';

const axios = Axios.create({
  baseURL: '/api/',
  withCredentials: true,
  paramsSerializer: params => queryString.stringify(params),
});

class HttpError extends Error {
  constructor(status, error, errors = {}) {
    super(`Http Error: ${status}`);
    this.status = status;
    this.error = error;
    this.errors = errors;   
  }

  getReduxFormError = defaultError => new SubmissionError({
    _error: this.error || defaultError,
    ...this.errors,
  });
}

const handleUnauth = (method, url, options) => (err) => {
  const { status } = err.response;

  if (status === 401) {
    return axios.get('/users/refresh')
      .then(() => method(url, options))
      .catch(() => Promise.reject(err));
  }

  return Promise.reject(err);
};

const handleHttpError = (err) => {
  const { status, data: { message = {} } } = err.response;
  if (typeof message === 'string') {
    return Promise.reject(new HttpError(status, message));
  }

  return Promise.reject(new HttpError(status, null, message));
};

const http = {
  get: (url, options) => axios.get(url, options)
    .then(response => response.data)
    .catch(handleUnauth(axios.get, url, options))
    .catch(handleHttpError),
  post: (url, data, options) => axios.post(url, data, options)
    .then(response => response.data)
    .catch(handleUnauth(axios.post, url, options))
    .catch(handleHttpError),
  patch: (url, data, options) => axios.patch(url, data, options)
    .then(response => response.data)
    .catch(handleUnauth(axios.patch, url, options))
    .catch(handleHttpError),
  delete: (url, options) => axios.delete(url, options)
    .then(response => response.data)
    .catch(handleUnauth(axios.delete, url, options))
    .catch(handleHttpError),
};

export default {
  upload: upload(http)
};
我希望测试能够通过,因为返回的对象应该与预期的操作匹配,但它会出错。以下是完整的信息:

FAIL  src/modules/upload/upload.test.js
Upload module actions › Returns an array of files when calling actions.fetchFiles

TypeError: store.dispatch(...).then is not a function
  43 |     // );
  44 |
> 45 |    return store.dispatch(actions.fetchFiles()).then(() => {
     |
  46 |     expect(store.getActions()).toEqual(expectedActions);
  47 |    });
  48 |   });
  at Object.then (src/modules/upload/upload.test.js:45:52)

承诺何时/何地返回,我如何链接a。然后像上面链接的Redux测试示例一样运行?

据我所知,您想要调度
异步
操作,请使用
Redux thunk
进行此操作。如果查看文档,
存储。调度
返回调度的操作:。在您的例子中,
fetchFiles
返回一个带有
promise
属性的对象,因此您可以通过执行类似于
store.dispatch(actions.fetchFiles()).promise的操作来链接它。然后(()=>{})
@PaoloMoretti,我尝试了这个操作,但得到的错误是.promise不是函数<代码>类型错误:store.dispatch(…).promise不是函数
`>45 |返回store.dispatch(actions.fetchFiles()).promise()。然后(()=>{`@RohitKashyap,谢谢你的建议。应用程序已经在生产中使用
redux-thunk
进行异步操作,并且在那里工作得很好;但是,我的测试代码失败了,那就是使用
redux-mock-store
来测试redux异步操作。也就是说,我仍然认为我无法链接我的
。然后()
返回承诺。@J2G
promise
确实不是一个函数,你应该删除
promise
之间的函数调用,然后
。据我所知,你想要调度
async
操作,使用
redux thunk
来实现。如果你查看文档,
store.dispatch
returns调度的操作:。在您的示例中,
fetchFiles
返回一个具有
promise
属性的对象,因此您可以通过执行类似于
store.dispatch(actions.fetchFiles()).promise的操作来链接它。然后(()=>{})
@PaoloMoretti,我试过了,但得到的错误是.promise不是函数。
TypeError:store.dispatch(…).promise不是函数
`>45 | return store.dispatch(actions.fetchFiles()).promise()。然后(()=>{`@RohitKashyap,谢谢你的建议。应用程序已经在生产中使用
redux-thunk
进行异步操作,并且在那里工作得很好;但是,我的测试代码失败了,那就是使用
redux-mock-store
来测试redux异步操作。也就是说,我仍然认为我无法链接我的
。然后()
返回承诺。@J2G
promise
确实不是一个函数,您应该删除
promise
之间的函数调用,然后
FAIL  src/modules/upload/upload.test.js
Upload module actions › Returns an array of files when calling actions.fetchFiles

TypeError: store.dispatch(...).then is not a function
  43 |     // );
  44 |
> 45 |    return store.dispatch(actions.fetchFiles()).then(() => {
     |
  46 |     expect(store.getActions()).toEqual(expectedActions);
  47 |    });
  48 |   });
  at Object.then (src/modules/upload/upload.test.js:45:52)