reactjs - react - redux axios request
¿Maneja solicitudes asíncronas con React, Redux y Axios? (4)
Los creadores de acciones de Redux aparentemente no admiten acciones asincrónicas, que es lo que estás tratando de hacer con la solicitud de publicación. Redux Thunk debería ayudar con esto.
Querrás un archivo store.js que tenga este aspecto:
//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
);
Así es como se vería su archivo de acciones. Crear se convierte en un creador de acciones que devuelve una función que luego realiza la solicitud de publicación y le permite realizar el envío allí, lo que le permite actualizar su tienda / estado. :
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);
})
}
}
Además, querrá pasar el método onSubmit que creó en onSubmitForm de esta manera. No estoy seguro de dónde proviene isLoading porque no lo veo importado en ese componente del contenedor, por lo que es posible que desee ver eso también:
<createOrganization onSubmitForm={this.onSubmit.bind(this)} isLoading={isLoading} />
Soy nuevo en React JS y Redux y ha sido demasiado abrumador para empezar. Estoy tratando de hacer una solicitud POST usando Axios, pero no puedo hacerlo. Puede ser que me falta algo en el archivo contenedor. Debajo está el código. Compruebe plnkr
Actualización: recibo el mensaje @@ redux-form / SET_SUBMIT_SUCCEEDED después de enviarlo. Pero cuando reviso la pestaña de red, no veo la llamada a la API. Y también cuando estoy consolando los valores enviados, solo veo valores de nombre y nombre completo. No consta de logotipo y detalles. ¿Qué me estoy perdiendo?
Archivo componente
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)
Archivo contenedor
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)
Puede hacerlo fácilmente con la ayuda de redux-saga.
Sobre redux-saga:
redux-saga
es una biblioteca que tiene como objetivo hacer que los efectos secundarios de la aplicación (es decir, cosas asincrónicas como la obtención de datos y cosas impuras como acceder al caché del navegador) sean más fáciles de administrar, más eficientes de ejecutar, simples de probar y mejores para manejar fallas.
Instalación:
$ npm install --save redux-saga
o
$ yarn add redux-saga
Consulte el enlace: https://github.com/redux-saga/redux-saga
Sugeriría usar
redux-promise-middleware
.
Esta biblioteca requiere que la acción tenga una propiedad llamada
payload
que es una
promesa
y esto es fácil con
axios
.
Luego se integra con
Redux
para
GET_CUSTOMERS
tipo de acción raíz (por ejemplo,
GET_CUSTOMERS
) con
PENDING
,
FULFILLED
y
REJECTED
y dispara esas acciones.
Disparar la acción es lo mismo que cualquier otra acción.
Almacenar
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);
Acción
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));
};
}
Reductor
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;
}
}
Sus creadores de acciones redux deben ser simples, objeto y deben despachar y actuar con un
type
clave obligatoria.
Sin embargo, utilizando middlewares personalizados como
redux-thunk
, podría llamar a la solicitud
axios
dentro de sus creadores de acciones, ya que sin
middlewares
personalizados sus creadores de acciones necesitan devolver un objeto plano
Tu creador de acción se verá así
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});
})
}
}
y tu reductor se verá así
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
}
}
ahora mientras creas la tienda puedes hacerlo como
import thunk from ''redux-thunk'';
import { createStore, applyMiddleware } from ''redux'';
const store = createStore(
reducer,
applyMiddleware(thunk)
);
Aparte de esto, también debe configurar el formulario redux
necesita usar combineReducers y Provider para pasar a la tienda
import reducer from ''./reducer'';
import { combineReducers } from ''redux'';
import { reducer as formReducer } from ''redux-form''
export const rootReducer = combineReducers({
reducer,
form: formReducer
})