2015-11-24 13 views
52

私が知っている限り、私はaction createでリクエストを書く必要があります。要求を提出するための約束をどのように使用するのですか?私は実際にデータを取得しています。その後、減速機に新しい状態が作成されます。接続時にアクションとレデューサーをバインドします。しかし、私は要求のために約束を使う方法を知らない。AJAXリクエストを還元する方法

アクション

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; 

答えて

12
あなたは(あなたがそれを引数として渡した場合)、コールバック内 dispatchを使用することができるはず

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

還元剤のaction.dataプロパティにアクセスする必要があります。

+0

ありがとうございますが、警告が表示されます:propTypeに失敗しました:必要なprop 'books'が' booksPage'に指定されていません。 (プログラム):(プログラム):45警告:getDefaultPropsは、従来のReact.createClass定義でのみ使用されています。代わりに 'defaultProps'という静的プロパティを使用してください。 –

+0

'action.data'を状態に減らしましたか? –

+0

Object.assign({}、状態、{ 書籍:action.data.books、 著者:action.data.authors }); –

49

すでにreduxを使用しているので、非同期アクションを定義できるようにする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 }; 
} 
20

はあなたがここRedux Documentation

非同期アクションの減速機の例で説明した非同期アクションを使用する必要があります。

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

export default booksReducer; 

次に、非同期アクションを作成します。

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の-サンクミドルウェアを使用して、アクションに(代わりにオブジェクトの)約束を返すことができます。
  • jQuery ajaxライブラリを使用しないでください。そのために別のライブラリを使用してください(例:fetch())。私はaxios http clientを使用します。
  • reduxでは、純粋な関数を減算器でのみ使用することを覚えておいてください。減速機の中でajaxコールをしないでください。
  • redux docsから完全なガイドを読んでください。
7

アクションクリエイターを「純粋な」状態に保つために、懸念事項を分けておきたいことがあります。

溶液;ミドルウェアを書く。例えば、これを取る(スーパーエージェントを使って)。

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

これをすべてモジュールに入れます。

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

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

プロパティ「薬」は、着信を派遣し、ネットワーク上に構築要求を送信ミドルウェア、によってピックアップされます。さて、あなたは「認証」と呼ばれるアクションの作成者がいる場合があります

あなたの店に結果。あなたはフックを定義した後

あなたの減速は、このすべてを処理します。

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

このすべては、あなたがすでにバニラJSに、es2015からtranspileと反応し、WebPACKの、ロールアップか何かを使用してパイプラインを設定する意味します。

関連する問題