Javascript Redux:从web服务访问状态的正确方法?
我已经概述了几种可能从web服务访问状态的方法,但我不知道在react redux应用程序中哪种方法是正确的,或者下面是否列出了正确的方法 上下文: 最初,我有一个Javascript Redux:从web服务访问状态的正确方法?,javascript,redux,react-redux,redux-thunk,redux-middleware,Javascript,Redux,React Redux,Redux Thunk,Redux Middleware,我已经概述了几种可能从web服务访问状态的方法,但我不知道在react redux应用程序中哪种方法是正确的,或者下面是否列出了正确的方法 上下文: 最初,我有一个API.js文件作为web服务的基础。然后我会将其导入到我的操作文件中。在我需要从API.js访问state(更具体地说,是我头部所需的状态中的web令牌)之前,这一切都进行得很顺利。我试图导入我的存储,但它返回了未定义的。然后我意识到我有一个循环依赖: api->store->reducers->components->action
API.js
文件作为web服务的基础。然后我会将其导入到我的操作文件中。在我需要从API.js
访问state(更具体地说,是我头部所需的状态中的web令牌)之前,这一切都进行得很顺利。我试图导入我的存储,但它返回了未定义的
。然后我意识到我有一个循环依赖:
api->store->reducers->components->actions
自定义中间件
我想知道这是否可以接受。我抛弃了我的
API.js
。我使用它来自动修改具有特定操作类型的传出网络呼叫。这就是我的中间件堆栈的外观:
const middleware = applyMiddleware(
myCustomModifyRequestMiddleware,
thunk,
. . .
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)
}
而myCustomModifyRequestMiddleware
基本上看起来像:
const middleware = applyMiddleware(
myCustomModifyRequestMiddleware,
thunk,
. . .
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\u ActionCreator
的动作创建者。但是嘿,如果我只是想用一个动作创造者为什么不
砰的一声
使用thunks,我可能只需要像
API\u 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...
现在,我可以将我的API\u ActionCreator
导入到我的操作中,而无需任何循环依赖项
订阅商店?
另一种方法是让web服务是有状态的;订阅商店
中的商店或web服务
,如果我在操作中调用web服务时能够避免遇到循环依赖关系的话
TLDR强>
当然,这都是实验性的,尽管我能够让中间件工作
我不知道哪一种是最可行的方法,是否有更适合redux的方法?Thunk action creators和集中式中间件都是在redux中管理API调用的标准方法,同时可以访问
dispatch
和getState`。这两个都可以
有关更多信息,请参阅Dan关于和的回答,以及我的文章的Redux副作用部分中的其他文章。您可能还对my中的列表感兴趣。我想与您分享一种方法,我们在为不同服务之间的获取请求创建标头选项时,遇到需要访问身份验证令牌的问题时使用了这种方法 我们最终使用单例模式创建了一个API服务,该服务将负责:
- 在整个使用过程中保留单个实例
- 持有所有服务使用的属性,如_令牌
- 公开可由服务使用的获取方法,以使用令牌设置默认头并发出请求
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);
在页面刷新时,如果令牌未定义,请确保它可以从初始状态重新水合
例如,将此方法添加到配置存储并具有初始状态访问权限的根或应用程序组件中
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;
},
})
希望这是有帮助的