如何在Reduce中创buildAJAX请求
就我所知,我必须在行动中编写请求创build。 如何使用承诺提交请求? 我正在获取数据。 然后在减速器中创build新的状态。 绑定动作和减速器连接。 但我不知道如何使用诺言的要求。
行动
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; }) }; }
减速器
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;
容器如何在容器中显示数据?
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;
由于您已经在使用redux,所以您可以应用允许您定义asynchronous操作的redux-thunk
中间件。
安装和使用: 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 }; }
您应该使用Redux文档中描述的asynchronous操作
这里是一个asynchronous动作减速器的例子。
const booksReducer = (state = {}, action) => { switch (action.type) { case 'RESOLVED_GET_BOOK': return action.data; default: return state; } }; export default booksReducer;
然后你创build你的asynchronous操作。
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 } }
几个注释:
- 我们可以通过使用redux-thunk中间件来返回Promise(而不是Object)。
- 不要使用jQuery ajax库。 使用其他库专门做这个(例如fetch())。 我使用axios http客户端 。
- 请记住,在redux中,您只能在reducer中使用纯函数。 减速器内部不要打ajax。
- 阅读完整的指南从REDX文档。
你应该可以在callback中使用dispatch
(如果你把它作为parameter passing):
export default function getBook(dispatch) { $.ajax({ method: "GET", url: "/api/data", dataType: "json" }).success(function(data){ return dispatch({type:'GET_BOOK', data: data}); }); }
然后,通过dispatch
行动:
function mapDispatchToProps(dispatch) { return { getBooks: () => getBook(dispatch), }; }
现在,您应该可以访问reducer中的action.data
属性:
const booksReducer = (state = initialState, action) => { switch (action.type) { case GET_BOOK: //action.data <--- here return state; default: return state; } };
您可能需要分开关注,以保持行动创造者“纯”。
解; 写一些中间件。 以此为例(使用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); };
把所有这些放在一个模块中。
现在,您可能会有一个名为“auth”的动作创build器:
export const auth = (username,password) => { return { type: 'AUTHENTICATE', agent: { url: '/auth', method: 'post', resourceName: 'user', params: { username, password } } }; };
物业的“代理”将由中间件提取,中间件通过networking发送构build的请求,然后将传入的结果发送到您的商店。
在您定义钩子后,您的reducer将处理所有这些事情:
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; } };
现在将所有这些注入到您的视图逻辑中。 我以反应为例。
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);
所有这一切意味着你已经使用webpack,rollup或者其他东西来build立一个pipe道,从es2015开始转换,然后对vanilla js做出反应。