Comment faire une requête AJAX en redux

Pour tout ce que je sais, je dois écrire des demandes en action créer. Comment utiliser une promesse en action pour soumettre une demande? Je reçois des données en action. Ensuite, un nouvel état est créé dans le réducteur. Action de liaison et réducteur en connexion. Mais je ne sais pas comment utiliser promis pour la demande.

action

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; }) }; } 

Réducteur

 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; 

Conteneur Comment afficher les données dans un conteneur?

 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 ( 
All Authors
    {books.map((book, index) =>
  • "{book.name}"
    {book.author}
  • )}
); } } export default booksPage;

Comme vous utilisez déjà redux, vous pouvez appliquer un middleware redux-thunk qui vous permet de définir des actions asynchrones.

Installation et utilisation: 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 }; } 

Vous devez utiliser les actions asynchrones décrites dans la documentation Redux

Voici un exemple de réducteur pour action asynchrone.

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

et puis vous créez votre action asynchrone.

 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 } } 

Plusieurs notes:

  • Nous pourrions retourner Promise (au lieu d’Object) en action en utilisant un middleware redux-thunk.
  • Ne pas utiliser la bibliothèque ajax jQuery. Utilisez une autre bibliothèque spécifiquement pour le faire (par exemple, fetch ()). J’utilise le client axios http .
  • Rappelez-vous, en redux, vous utilisez uniquement la fonction pure dans le réducteur. Ne faites pas un appel ajax à l’intérieur du réducteur.
  • Lisez le guide complet de redux docs.

Vous devriez pouvoir utiliser dispatch dans le callback (si vous le transmettez en argument):

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

Ensuite, passez l’ dispatch à l’action:

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

Maintenant, vous devriez avoir access à la propriété action.data dans le réducteur:

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

Vous pouvez vouloir séparer les préoccupations, pour garder les créateurs d’action “purs”.

Solution; écrire un middleware. Prenez cela par exemple (en utilisant superagent).

 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); }; 

Mettez tout cela dans un module.

Maintenant, vous pourriez avoir un créateur d’action appelé «auth»:

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

La propriété ‘agent’ sera captée par le middleware, qui envoie la requête construite sur le réseau, puis dissortingbue le résultat entrant à votre magasin.

Votre réducteur gère tout cela après avoir défini les hooks:

 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; } }; 

Maintenant, injectez tout cela dans votre logique de vue. J’utilise comme exemple.

 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 ''; /* 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 = (    ); const entryElement = document.getElementById('app'); ReactDOM.render(provider, entryElement); 

Tout cela implique que vous avez déjà configuré un pipeline en utilisant webpack, rollup ou quelque chose, pour passer de es2015 et réagir, à vanilla js.