what react example actions ajax reactjs request redux

react - Cómo hacer una solicitud AJAX en redux



redux http request (4)

Por lo que sé, tengo que escribir solicitud en acción crear. ¿Cómo usar una promesa en acción para enviar una solicitud? Estoy poniendo datos en acción. Entonces se crea un nuevo estado en reductor. Acción de unión y reductor en conexión. Pero no sé cómo usar Promesa de solicitud.

Acción

import $ from ''jquery''; export const GET_BOOK = ''GET_BOOK''; export default function getBook() { return { type: GET_BOOK, data: $.ajax({ method: "GET", url: "/api/data", dataType: "json" }).success(function(data){ return data; }) }; }

Reductor

import {GET_BOOK} from ''../actions/books''; const booksReducer = (state = initialState, action) => { switch (action.type) { case GET_BOOK: return state; default: return state; } }; export default booksReducer;

Contenedor ¿Cómo mostrar datos en contenedor?

import React, { Component, PropTypes } from ''react''; import { connect } from ''react-redux''; import getBook from ''../actions/books''; import Radium from ''radium''; import {Link} from ''react-router''; function mapStateToProps(state) { return { books: state.data.books, }; } function mapDispatchToProps(dispatch) { return { getBooks: () => dispatch(getBook()), }; } @Radium @connect(mapStateToProps, mapDispatchToProps) class booksPage extends Component { static propTypes = { getBooks: PropTypes.func.isRequired, books: PropTypes.array.isRequired, }; render() { const {books} = this.props; return ( <div> <Link to={`/authors`}><MUIButton style="flat">All Authors</MUIButton></Link> <ul> {books.map((book, index) => <li key={index}> <Link to={`/book/${book.name}`}><MUIButton style="flat"><div class="mui--text-black mui--text-display4"> "{book.name}"</div></MUIButton></Link> <Link to={`/author/${book.author}`}><MUIButton style="flat"><div class="mui--text-black mui--text-display4"> {book.author}</div></MUIButton></Link> </li> )} </ul> </div> ); } } export default booksPage;


Como ya está utilizando redux, puede aplicar el middleware redux-thunk que le permite definir acciones asincrónicas.

Instalación y uso: Redux-thunk

export function fetchBook(id) { return dispatch => { dispatch(setLoadingBookState()); // Show a loading spinner fetch(`/book/${id}`, (response) => { dispatch(doneFetchingBook()); // Hide loading spinner if(response.status == 200){ dispatch(setBook(response.json)); // Use a normal function to set the received state }else { dispatch(someError) } }) } } function setBook(data) { return { type: ''SET_BOOK'', data: data }; }


Debe usar las acciones asíncronas descritas en la documentación de Redux

Aquí un ejemplo de reductor para la acción asíncrona.

const booksReducer = (state = {}, action) => { switch (action.type) { case ''RESOLVED_GET_BOOK'': return action.data; default: return state; } }; export default booksReducer;

y luego creas tu acción asíncrona.

export const getBook() { return fetch(''/api/data'') .then(response => response.json()) .then(json => dispatch(resolvedGetBook(json))) } export const resolvedGetBook(data) { return { type: ''RESOLVED_GET_BOOK'', data: data } }

Varias notas:

  • Podríamos devolver Promise (en lugar de Object) en acción mediante el uso de middleware redux-thunk.
  • No use la biblioteca jQuery ajax. Use otra biblioteca específicamente para hacerlo (por ejemplo, fetch ()). Yo uso axios http client .
  • Recuerde, en redux solo usa la función pura en reductor. No haga llamadas ajax dentro del reductor.
  • Lea la guía completa de documentos de redux.

Debería poder usar el dispatch dentro de la devolución de llamada (si lo pasa como argumento):

export default function getBook(dispatch) { $.ajax({ method: "GET", url: "/api/data", dataType: "json" }).success(function(data){ return dispatch({type:''GET_BOOK'', data: data}); }); }

Luego, pase el dispatch a la acción:

function mapDispatchToProps(dispatch) { return { getBooks: () => getBook(dispatch), }; }

Ahora, debe tener acceso a la propiedad action.data en el reductor:

const booksReducer = (state = initialState, action) => { switch (action.type) { case GET_BOOK: //action.data <--- here return state; default: return state; } };


Es posible que desee separar las preocupaciones, para mantener los creadores de acción "puros".

Solución; Escribe un middleware. Tome esto por ejemplo (usando superagente).

import Request from ''superagent''; const successHandler = (store,action,data) => { const options = action.agent; const dispatchObject = {}; dispatchObject.type = action.type + ''_SUCCESS''; dispatchObject[options.resourceName || ''data''] = data; store.dispatch(dispatchObject); }; const errorHandler = (store,action,err) => { store.dispatch({ type: action.type + ''_ERROR'', error: err }); }; const request = (store,action) => { const options = action.agent; const { user } = store.getState().auth; let method = Request[options.method]; method = method.call(undefined, options.url) if (user && user.get(''token'')) { // This example uses jwt token method = method.set(''Authorization'', ''Bearer '' + user.get(''token'')); } method.send(options.params) .end( (err,response) => { if (err) { return errorHandler(store,action,err); } successHandler(store,action,response.body); }); }; export const reduxAgentMiddleware = store => next => action => { const { agent } = action; if (agent) { request(store, action); } return next(action); };

Pon todo esto en un módulo.

Ahora, puede tener un creador de acción llamado ''auth'':

export const auth = (username,password) => { return { type: ''AUTHENTICATE'', agent: { url: ''/auth'', method: ''post'', resourceName: ''user'', params: { username, password } } }; };

El ''agente'' de la propiedad será recogido por el middleware, que envía la solicitud construida a través de la red y luego envía el resultado entrante a su tienda.

Su reductor maneja todo esto, después de definir los ganchos:

import { Record } from ''immutable''; const initialState = Record({ user: null, error: null })(); export default function auth(state = initialState, action) { switch (action.type) { case ''AUTHENTICATE'': return state; case ''AUTHENTICATE_SUCCESS'': return state.merge({ user: action.user, error: null }); case ''AUTHENTICATE_ERROR'': return state.merge({ user: null, error: action.error }); default: return state; } };

Ahora inyecta todo esto en tu lógica de vista. Estoy usando reaccionar como ejemplo.

import React from ''react''; import ReactDOM from ''react-dom''; /* Redux + React utils */ import { createStore, applyMiddleware, bindActionCreators } from ''redux''; import { Provider, connect } from ''react-redux''; // thunk is needed for returning functions instead // of plain objects in your actions. import thunkMiddleware from ''redux-thunk''; // the logger middleware is useful for inspecting data flow import createLogger from ''redux-logger''; // Here, your new vital middleware is imported import { myNetMiddleware } from ''<your written middleware>''; /* vanilla index component */ import _Index from ''./components''; /* Redux reducers */ import reducers from ''./reducers''; /* Redux actions*/ import actionCreators from ''./actions/auth''; /* create store */ const store = createStore( reducers, applyMiddleware( thunkMiddleware, myNetMiddleware ) ); /* Taint that component with store and actions */ /* If all goes well props should have ''auth'', after we are done */ const Index = connect( (state) => { const { auth } = state; return { auth }; }, (dispatch) => { return bindActionCreators(actionCreators, dispatch); })(_Index); const provider = ( <Provider store={store}> <Index /> </Provider> ); const entryElement = document.getElementById(''app''); ReactDOM.render(provider, entryElement);

Todo esto implica que ya configuró una tubería utilizando webpack, rollup o algo así, para transpilar de es2015 y reaccionar, a vanilla js.