2015-11-24 4 views
52

Nach allem, was ich weiß, muss ich Anfrage in Aktion erstellen erstellen. Wie verwende ich ein Versprechen, um eine Anfrage zu senden? Ich bekomme Daten in Aktion. Dann wird ein neuer Zustand in dem Reduzierer erzeugt. Bind Aktion und Reducer in Verbindung. Aber ich weiß nicht, wie man Versprechen für eine Anfrage verwendet.Wie AJAX-Anfrage in Redux machen

Aktion

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 Wie Anzeigedaten in Container?

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; 

Antwort

12

Sie sollten in der Lage dispatch innerhalb der Callback zu verwenden (wenn Sie es als Argument übergeben):

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

Dann dispatch an die Aktion übergeben:

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

Jetzt , sollten Sie Zugriff auf die action.data Eigenschaft in der Reduzierung haben:

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

danke, aber jetzt bekomme ich Warnung: fehlgeschlagen propType: Erforderliche prop 'Bücher' wurde nicht in' booksPage' angegeben. Überprüfen Sie die Rendermethode 'Connect (booksPage)' .warning @ (program): 45 (Programm): 45 Warnung: getDefaultProps wird nur für klassische React.createClass-Definitionen verwendet. Verwenden Sie stattdessen eine statische Eigenschaft namens 'defaultProps'. –

+0

Haben Sie die 'action.data' in den Status reduziert? –

+0

Object.assign ({}, state, { books: action.data.books, Autoren: action.data.authors }); –

49

Da Sie bereits Redux verwenden, können Sie redux-thunk Middleware anwenden, mit der Sie asynchrone Aktionen definieren können.

Installations & Nutzung: 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

Sie sollten in Redux Documentation

Hier ein Beispiel für Minderer für Asynchron-Aktion beschrieben Async Aktionen verwenden.

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

export default booksReducer; 

und dann erstellen Sie Ihre Async-Aktion.

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

Mehrere Hinweise:

  • Wir konnten Versprechen zurückzukehren (statt Object) in Aktion von redux-Thunk Middleware.
  • Verwenden Sie keine jQuery Ajax-Bibliothek. Verwenden Sie dafür eine andere Bibliothek (z. B. fetch()). Ich benutze axios http client.
  • Denken Sie daran, in redux verwenden Sie nur reine Funktion in Reducer. Machen Sie keinen Ajax innerhalb des Reduzierers.
  • Lesen Sie den kompletten Leitfaden von redux docs.
7

Sie könnten Bedenken trennen, um Aktionsersteller "rein" zu halten.

Lösung; schreibe etwas Middleware. Nehmen Sie dies zum Beispiel (mit Superagenten).

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

Setzen Sie das alles in ein Modul.

Jetzt könnten Sie eine Aktion creator ‚Auth‘ genannt haben:

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

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

Die Eigenschaft ‚Agent‘ wird von der Middleware abgeholt werden, die die konstruierte Anfrage über das Netzwerk sendet, dann sendet die eingehenden Ergebnis zu Ihrem Geschäft.

Ihr Minderer behandelt dies alles, nachdem Sie die Haken definieren:

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

Jetzt injizieren all dies in Ihrer Ansicht Logik. Ich benutze das als Beispiel.

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

All dies bedeutet, dass Sie bereits eine Pipeline mit webpack, Rollup oder etwas, von es2015 und reagieren auf Vanille js transpile einzurichten.