2015-11-24 18 views
52

Per quanto ne so, devo scrivere la richiesta in action create. Come utilizzare una promessa in atto per l'invio di una richiesta? Sto ottenendo dati in azione. Quindi il nuovo stato viene creato nel riduttore. Collega azione e riduttore. Ma non so come usare la promessa per la richiesta.Come fare una richiesta AJAX in redux

azione

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

Reducer

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; 

Container Come visualizzare i dati in un contenitore?

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; 

risposta

12

Si dovrebbe essere in grado di utilizzare dispatch all'interno del callback (se si passa come argomento):

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

Poi, passare dispatch all'azione:

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

Ora , si dovrebbe avere accesso alla proprietà action.data nel riduttore:

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

grazie, ma ora ricevo Avviso: Impossibile propType: obbligatorio 'libri' non è stato specificato in' booksPage'. Controllare il metodo di rendering di 'Connect (booksPage)' .warning @ (programma): 45 (programma): 45 Avviso: getDefaultProps viene utilizzato solo nelle classiche definizioni React.createClass. Utilizzare invece una proprietà statica denominata 'defaultProps'. –

+0

Hai ridotto 'action.data' in stato? –

+0

Object.assign ({}, stato, { libri: action.data.books, autori: action.data.authors }); –

49

Poiché si sta già utilizzando Redux, è possibile applicare il middleware redux-thunk che consente di definire azioni asincrone.

installazione & utilizzo: 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 }; 
} 
20

si dovrebbe usare azioni asincrone descritti in Redux Documentation

Ecco un esempio di riduttore per l'azione asincrona.

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

export default booksReducer; 

e quindi si crea l'azione Async.

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

Diversi Note:

  • potevamo tornare Promise (anziché Object) in azione utilizzando Redux-thunk middleware.
  • Non utilizzare la libreria jQuery ajax. Usa l'altra libreria specificatamente per farlo (ad es. Fetch()). Io uso axios http client.
  • Ricordate, in redux usate solo la pura funzione nel riduttore. Non effettuare una chiamata di jax all'interno del riduttore.
  • Leggi la guida completa dai documenti di redux.
7

Si potrebbe voler separare le preoccupazioni, per mantenere i creatori di azioni "puri".

Soluzione; scrivere un po 'di middleware. Prendi questo ad esempio (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); 
}; 

Mettere tutto questo in un modulo.

Ora, si potrebbe avere un creatore azione chiamata 'auth':

export const auth = (username,password) => { 

    return { 
     type: 'AUTHENTICATE', 
     agent: { 
      url: '/auth', 
      method: 'post', 
      resourceName: 'user', 
      params: { 
       username, 
       password 
      } 
     } 
    }; 
}; 

L' 'agente' immobile sarà raccolto dal middleware, che invia la richiesta costruito attraverso la rete, quindi invia l'ingresso risultato al tuo negozio.

tuo riduttore gestisce tutto questo, dopo aver definito i ganci:

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

punto, iniettare tutto questo nella vostra logica vista. Sto usando reagire come esempio.

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

Tutto questo implica che si già impostato una pipeline utilizzando webpack, rollup o qualcosa, per transpile da es2015 e reagire, a js vaniglia.

Problemi correlati