Traiter une requête asynchrone avec React, Redux et Axios?
Je suis nouveau pour réagir JS et Redux et il a été trop accablant pour aller de l'avant. Je suis en train de faire une requête POST à l'aide de Axios, mais je suis incapable de le faire. Il se peut que je manque quelque chose dans le dossier des conteneurs. Ci-dessous est le code. Vérifier plnkr
mise à Jour: je reçois @@ @ redux-form / SET_SUBMIT_SUCCEEDEDED message après avoir soumis. Mais quand je vérifie l'onglet Réseau, Je ne vois pas l'appel à L'API. Et aussi quand je consolerai le soumis valeurs, Je ne vois que les valeurs nom et fullname. Il ne se compose pas de logo et de détails. Ce qui me manque?
fichier de composants
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)
Fichier Conteneur
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)
4 réponses
vos créateurs d'action redux doivent être simples, objet et doivent envoyer et agir avec une clé obligatoire type
. Cependant en utilisant des middlewares personnalisés comme redux-thunk
on pourrait appeler axios
demande au sein de votre action de créateurs sans personnalisé middlewares
vos créateurs d'action doivent retourner l'objet simple
votre créateur d'action ressemblera à
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});
})
}
}
et votre réducteur
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
}
}
maintenant, tout en créant le magasin, vous pouvez le faire comme
import thunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';
const store = createStore(
reducer,
applyMiddleware(thunk)
);
en dehors de cela, vous devez également configurer le formulaire redux
vous devez utiliser combineReducers et Provider pour passer sur le magasin
import reducer from './reducer';
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form'
export const rootReducer = combineReducers({
reducer,
form: formReducer
})
Vous pouvez le faire facilement avec l'aide de redux-saga.
à Propos de redux-saga:
redux-saga
est une bibliothèque qui vise à rendre les effets secondaires de l'application (c.-à-d. des choses asynchrones comme la collecte de données et des choses impures comme l'accès au cache du navigateur) plus faciles à gérer, plus efficaces à exécuter, simples à tester, et mieux à gérer les échecs.
Installation:
$ npm install --save redux-saga
ou
$ yarn add redux-saga
référez-vous au lien : https://github.com/redux-saga/redux-saga
les créateurs D'action Redux ne supportent apparemment pas les actions asynchrones, ce que vous essayez de faire avec la requête post. Redux Thunk devrait vous aider.
Vous aurez besoin d'un magasin.fichier js qui ressemble à ceci:
//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
);
voici à quoi ressemblerait votre fichier actions. Create devient un créateur d'action qui retourne une fonction qui exécute alors la requête post et vous permet d'y effectuer l'expédition vous permettant de mettre à jour votre store/état. :
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);
})
}
}
aussi, vous voudrez passer dans la méthode onSubmit que vous avez créée dans onSubmitForm comme ceci. Je ne suis pas sûr d'où vient isLoading parce que je ne le vois pas importé dans ce composant de conteneur donc vous pourriez vouloir regarder cela aussi.:
<createOrganization onSubmitForm={this.onSubmit.bind(this)} isLoading={isLoading} />
je suggère d'utiliser redux-promesse-de middleware. Cette bibliothèque exige que l'action ait une propriété nommée payload
c'est un promesse et c'est facile avec axios
. Il intègre ensuite avec Redux
pour le suffixe de la racine du type d'action (par exemple,GET_CUSTOMERS
) avec PENDING
,FULFILLED
et REJECTED
et déclenche ces actions.
tirer l'action est la même que toute autre action.
Magasin
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);
Action
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));
};
}
Réducteur
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;
}
}