3

我已经概述了几种可能从 Web 服务访问状态的方法,但我不知道在 react-redux 应用程序中哪一种是正确的,或者下面是否列出了正确的一种。

语境:

最初,我有一个API.js文件作为 Web 服务的基础。然后我会将它导入到我的操作文件中。这进展顺利,直到我需要API.js. 我试图导入我的商店,但它返回了undefined. 然后我意识到我有一个循环依赖:

api -> store -> reducers -> components -> actions

自定义中间件


我想知道这是否可以接受。我放弃了我的API.js. 我使用它来自动修改具有特定操作类型的传出网络调用。这是我的中间件堆栈的样子:

const middleware = applyMiddleware(
    myCustomModifyRequestMiddleware,
    thunk,
    . . .

myCustomModifyRequestMiddleware基本上看起来像:

 const myCustomModifyRequestMiddleware = store => next => action {
     if(action.type === 'MODIFY_ME') {

         //Dispatch an FSA
         store.dispatch({
             type: action.payload.actual_type,
             payload: axios.create({ . . .
             meta: action.meta
         })
     }

     return next(action)
 }

现在我的中间件中有业务逻辑!

然后我可以有一个名为API_ActionCreator. 但是,嘿,如果我只是要使用动作创建器,为什么不...

敲它


使用 thunk 我可能只是有类似的东西API_ActionCreator.js

const apiActionCreator = (actual_type, url, data . . .) {
    return (dispatch, store) {
        //Now I can get the state...
        store.getState()

        //Return an FSA
        return { 
            type: actual_type,
            payload: axios.create...

现在我可以将 my 导入API_ActionCreator到我的操作中,而无需任何循环依赖。

订阅商店?

另一种方法是让 Web 服务有状态;订阅store或中的商店web service,如果我在我的操作中调用我的 Web 服务时能以某种方式避免遇到循环依赖。

TLDR; 当然,这都是实验性的,尽管我能够让中间件工作。

我不知道哪一种是最可行的方法,是否有一种更 redux-ish 的方法来做到这一点?

4

2 回答 2

1

Thunk action creators 和集中式中间件都是在 Redux 中管理 API 调用的标准方法,同时可以访问dispatch和 getState`。其中任何一个都很好。

有关更多信息,请参阅 Dan 关于管理 Redux 中的异步行为以及为什么 thunk 和其他中间件对异步工作有用的答案,以及我的React/Redux 链接列表的 Redux 副作用部分中的其他文章。您可能还对我的Redux 插件目录中用于发出网络请求的 Redux 中间件列表感兴趣。

于 2017-07-14T15:44:37.557 回答
0

我想分享一种我们在为不同服务之间的获取请求创建标头选项时需要访问身份验证令牌的问题时使用的方法。

我们最终使用单例模式创建了一个 API 服务,该服务将负责:

  • 在整个使用过程中保持单个实例
  • 持有所有服务使用的属性,例如 _token
  • 公开一个 fetch 方法,服务可以使用该方法使用令牌设置默认标头并发出请求

这是服务的样子:

let _instance = null;

class ApiService {
  static getInstance() {
    if (_instance === null) {
      _instance = new ApiService();
    }

    return _instance;
  }

  setToken(token) {
    this._token = token;
  }

  defaultHeaders(immediateHeaders) {
    const headers = {
      'Content-type': 'application/json',
      ...immediateHeaders,
    };

    if (this._token) {
      headers['Authorization'] = `Bearer ${this._token}`;
    }

    return headers;
  }

  fetch(url, options) {
    const headers = this.defaultHeaders();

    const opts = {
      ...options,
      headers,
    };

    return fetch(url, opts);
  }
}

export default ApiService;

用法

使用这种方法时,首先要做的是在状态处理程序期间在服务上设置令牌属性,当令牌作为状态可用时,这些令牌会暴露给令牌。

例如,在身份验证状态处理程序中设置令牌是一个好的开始,因为令牌将从状态中可用,例如state.auth.token

为此,在您的登录成功操作中作为 thunk 或 saga 设置令牌,然后将用户重定向到可能依赖于获取的私有路由或特定组件:

ApiService.getInstance().setToken(token);

在页面刷新时,如果令牌未定义,请确保它可以从初始状态重新水化。

例如,将此方法添加到配置商店并有权访问初始状态的 Root 或 App 组件中。

if (initialState.auth.token) {
  ApiService.getInstance().setToken(initialState.auth.token);
}

当令牌设置为 ApiService 实例上的属性时,使用令牌从任何服务获取请求是很简单的。

只需导入 ApiService 并正常获取,但使用公共获取方法。

进行提取时,正常传递 URL 和任何相关选项,例如方法或正文,除了默认情况下使用 auth 令牌设置的标头。

import ApiService from './api.service';

// Get the API service instance

const api = ApiService.getInstance();

export default () => ({

  fetchWorkspaces: async () => {

    const response = await api.fetch(url);

    const workspaces = await response.json();

    return workspaces;

  },
})

希望这有帮助!

于 2018-03-22T18:55:41.397 回答