使用 React、Redux 和 Axios 处理异步请求?
Posted
技术标签:
【中文标题】使用 React、Redux 和 Axios 处理异步请求?【英文标题】:Handling async request with React, Redux and Axios? 【发布时间】:2018-05-12 11:14:31 【问题描述】:我是 React JS 和 Redux 的新手,而且太难开始了。我正在尝试使用 Axios 发出 POST 请求,但我无法做到。可能是我在容器文件中遗漏了一些东西。下面是代码。检查plnkr
更新:我在提交后收到@@redux-form/SET_SUBMIT_SUCCEEDED 消息。但是当我检查网络选项卡时,我没有看到对 API 的调用。而且当我安慰提交的值时,我只看到名称和全名值。它不包含徽标和细节。我错过了什么?
组件文件
import React, PureComponent from 'react'
import PropTypes from 'prop-types'
import Field,reduxForm from 'redux-form'
import Columns,Column, TextArea, Label,Button from 'bloomer'
import FormField from 'FormField'
const validate = (values) =>
const errors =
const requiredFields =
['organizationName','organizationFullName','organizationDetails']
requiredFields.forEach((field) =>
if (!values[field])
errors[field] = 'This field can\'t be empty!'
)
return errors
const formConfig =
validate,
form: 'createOrganization',
enableReinitialize: true
export class CreateOrganization extends PureComponent
static propTypes =
isLoading:PropTypes.bool.isRequired,
handleSubmit: PropTypes.func.isRequired, // from react-redux
submitting: PropTypes.bool.isRequired // from react-redux
onSubmit = data =>
console.log(data)
render ()
const handleSubmit,submitting,isLoading = this.props
return (
<Columns isCentered>
<form onSubmit=handleSubmit(this.onSubmit.bind(this)) >
<Column isSize='3/6' >
<Label>Organization Name</Label>
<Field
name="organizationName"
component=FormField
type="text"
placeholder="Organization Name"
/>
</Column>
<Column isSize='3/6'>
<Label>Organization Full Name</Label>
<Field
name="organizationFullName"
component=FormField
type="text"
placeholder="Organization Full Name"
/>
</Column>
<Column isSize='3/6'>
<Label>Organization Logo</Label>
<Input
name="organizationLogo"
type="file"
placeholder="Logo"
/>
</Column>
<Column isSize='3/6'>
<Label>Organization Details</Label>
<TextArea placeholder='Enter Details' />
</Column>
<Column >
<span className="create-button">
<Button type="submit" isLoading=submitting || isLoading isColor='primary'>
Submit
</Button>
</span>
<Button type="button" isColor='danger'>
Cancel
</Button>
</Column>
</form>
</Columns>
)
export default reduxForm(formConfig)(CreateOrganization)
容器文件
import React, PureComponent from 'react'
import PropTypes from 'prop-types'
import connect from 'react-redux'
import Loader from 'Loader'
import organization from 'state/organization'
import CreateOrganization from '../components/createOrganization'
export class Create extends PureComponent
static propTypes =
error: PropTypes.object,
isLoaded: PropTypes.bool.isRequired,
create: PropTypes.func.isRequired,
onSubmit = data =>
this.props.create(data)
render ()
const isLoaded, error = this.props
return (
<CreateOrganization onSubmitForm=this.onSubmit isLoading=
isLoading />
)
const mapStateToProps = state => (
error: organization.selectors.getError(state),
isLoading: organization.selectors.isLoading(state)
)
const mapDispatchToProps =
create: organization.actions.create
export default connect(mapStateToProps, mapDispatchToProps)(Create)
【问题讨论】:
首先,人们会开始对这个问题投反对票,纯粹是因为格式很糟糕。使其难以阅读。如果您无法在此处获取格式,您可以发布一个 codepen 示例。其次,您应该更详细地描述您的需求。什么不工作?你能进入 callAPI 函数吗?响应没有得到控制台记录吗? 附注<CreateOrg onSubmit=this.props />
this.props
是一个对象不是一个函数
我无法进入调用 API 函数。感谢您的建议。将添加更改
onSubmit 应该指向 props 对象上的一个函数。
那个函数会在行动中声明?
【参考方案1】:
您的 redux 操作创建者必须是普通的对象,并且应该使用强制键 type
进行调度和操作。但是使用自定义中间件,如redux-thunk
,您可以在您的动作创建者中调用axios
请求,因为没有自定义middlewares
,您的动作创建者需要返回普通对象
你的动作创建者看起来像
export function create (values)
return (dispatch) =>
dispatch(type: CREATE_ORGANIZATION);
axios.post('/url', values)
.then((res) =>
dispatch(type: CREATE_ORGANIZATION_SUCCESS, payload: res);
)
.catch((error)=>
dispatch(type: CREATE_ORGANIZATION_FAILURE, payload: error);
)
你的减速器看起来像
export default (state = initialState, action) =>
const payload = action.payload
switch (action.type)
case CREATE:
return
...state,
loading: true,
loaded: false
case CREATE_SUCCESS:
return
...state,
data: state.data.concat(payload.data),
loading: false,
loaded: true,
error: null
case CREATE_FAILURE:
return
...state,
loading: false,
loaded: true,
error: payload
default:
return state
现在在创建商店时,您可以这样做
import thunk from 'redux-thunk';
import createStore, applyMiddleware from 'redux';
const store = createStore(
reducer,
applyMiddleware(thunk)
);
除此之外你还需要设置redux表单
你需要使用 combineReducers 和 Provider 来传递 store
import reducer from './reducer';
import combineReducers from 'redux';
import reducer as formReducer from 'redux-form'
export const rootReducer = combineReducers(
reducer,
form: formReducer
)
CodeSandbox
【讨论】:
检查此答案,如果您遇到任何困难,请告诉我 我仍然在控制台中收到'@@redux-form/SET_SUBMIT_FAILED' 我添加了一个包含所有错误纠正的代码沙箱,您需要使用 combineReducers 并在其中设置 redux-form。除此之外,还有其他错误,例如没有为组件使用大写字符。如果您仍然遇到麻烦,请告诉我 去看看。谢谢 您的配置似乎不允许 redux-thunk 提交触发您的 api 请求的操作。检查你的applyMiddleware( your_middleware?, thunk, logger)(createStore)
然后尝试在不使用redux-form
的情况下实现逻辑【参考方案2】:
你可以在 redux-saga 的帮助下轻松做到这一点。
关于redux-saga:
redux-saga
是一个库,旨在使应用程序的副作用(即数据获取之类的异步操作和访问浏览器缓存之类的不纯操作)更易于管理、执行效率更高、测试简单且更擅长处理故障.
安装:
$ npm install --save redux-saga
或
$ yarn add redux-saga
请参考链接:https://github.com/redux-saga/redux-saga
【讨论】:
【参考方案3】:Redux 操作创建者显然不支持异步操作,这是您尝试对发布请求执行的操作。 Redux Thunk 应该对此有所帮助。
您需要一个如下所示的 store.js 文件:
//npm install --save redux-thunk
import createStore, applyMiddleware from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducer.js';
// Note: this API requires redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk) //needed so you can do async
);
这是您的操作文件的外观。 Create 成为一个动作创建者,它返回一个函数,然后执行发布请求并允许您在那里进行调度,从而允许您更新您的商店/状态。 :
import axios from 'axios'
import CREATE_ORGANIZATION, CREATE_ORGANIZATION_SUCCESS, CREATE_ORGANIZATION_FAILURE,
from './constants'
import * as selectors from './selectors'
/*
CREATE ORGANIZATION
*/
//uses redux-thunk to make the post call happen
export function create (values)
return function(dispatch)
return axios.post('/url', values).then((response) =>
dispatch( type: 'Insert-constant-here')
console.log(response);
)
另外,您需要像这样将您创建的 onSubmit 方法传递到 onSubmitForm 中。我不确定 isLoading 来自哪里,因为我没有看到它在该容器组件中导入,因此您可能也想查看它。:
<createOrganization onSubmitForm=this.onSubmit.bind(this) isLoading=isLoading />
【讨论】:
'Insert-constant-here' 是不是像 CREATE_ORGANIZATION_SUCCESS 这样的操作类型? 是的,把动作类型放在那里。 我仍然在控制台中收到'@@redux-form/SET_SUBMIT_FAILED' 我更新了我的答案。我想你会想在那里做一些改变 仍然没有调用 API【参考方案4】:我建议使用redux-promise-middleware。这个库要求动作有一个名为payload
的属性,这是一个promise,这很容易用axios
。然后它与Redux
集成,以在根操作类型(例如GET_CUSTOMERS
)后缀PENDING
、FULFILLED
和REJECTED
并触发这些操作。
触发动作与任何其他动作相同。
商店
import applyMiddleware, compose, createStore from 'redux';
import promiseMiddleware from 'redux-promise-middleware';
import reducer from './reducers';
let middleware = applyMiddleware(promiseMiddleware());
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const enhancer = composeEnhancers(middleware);
export default createStore(reducer, enhancer);
动作
export function getCustomers()
return
type: 'GET_CUSTOMERS',
payload: axios.get('url/to/api')
.then(res =>
if (!res.ok) throw new Error('An error occurred.');
return res;
)
.then(res => res.json())
.catch(err => console.warn(err));
;
减速器
export default function(state = initialState, action) =>
switch (action.type)
case 'GET_CUSTOMERS_PENDING':
// this means the call is pending in the browser and has not
// yet returned a response
...
case 'GET_CUSTOMERS_FULFILLED':
// this means the call is successful and the response has been set
// to action.payload
...
case 'GET_CUSTOMERS_REJECTED':
// this means the response was unsuccessful so you can handle that
// error here
...
default:
return state;
【讨论】:
以上是关于使用 React、Redux 和 Axios 处理异步请求?的主要内容,如果未能解决你的问题,请参考以下文章
处理 axios react-redux 应用程序中的 401 未授权错误
React + redux + axios + thunk,等待interceptors.response 刷新token