2017-04-10 41 views
0

我使用的是this starter kit,下面的代碼可以在this fork上找到。使用Redux從還原器返回承諾

計數器組件:

export const Counter = (props) => (
    <div style={{ margin: '0 auto' }} > 
    <h2>Counter: {props.counter}</h2> 
    <button className='btn btn-default' onClick={props.double}> 
     Double (Async) 
    </button> 
    </div> 
) 
Counter.propTypes = { 
    counter  : React.PropTypes.number.isRequired, 
    double : React.PropTypes.func.isRequired, 
    increment : React.PropTypes.func.isRequired 
} 

export default Counter 

和容器組件:

import { connect } from 'react-redux' 
import { increment, double } from '../modules/counter' 

import Counter from '../components/Counter' 

const mapDispatchToProps = { 
    increment :() => increment(1), 
    double:() => double() 
} 

const mapStateToProps = (state) => { 
    return { 
    counter : state.counter 
    } 
} 

export default connect(mapStateToProps, mapDispatchToProps)(Counter) 

的行動:

export const COUNTER_INCREMENT = 'COUNTER_INCREMENT' 
export const COUNTER_DOUBLE = 'COUNTER_DOUBLE' 
// ------------------------------------ 
// Actions 
// ------------------------------------ 
export const increment = (value = 1) => { 
    return { 
    type: COUNTER_INCREMENT, 
    payload: value 
    } 
} 
export const double = (value = 0) => { 
    return { 
    type: COUNTER_DOUBLE, 
    payload: value 
    } 
} 

const doubleAsync = (state) => { 
    return (dispatch, getState) => { 
    return new Promise((resolve) => { 
     setTimeout(() => { 
     dispatch(increment(state)) 
     resolve() 
     }, 200) 
    }) 
    } 
} 

export const actions = { 
    increment, 
    double 
} 


const ACTION_HANDLERS = { 

    [COUNTER_INCREMENT]: function (state, action) { 
    return state + action.payload 
    }, 
    [COUNTER_DOUBLE]: (state, action) => { 
    return doubleAsync() 

    } 
    } 
} 

而減速:

const initialState = 0 
export default function counterReducer(state = initialState, action) { 
    const handler = ACTION_HANDLERS[action.type] 
    return handler ? handler(state, action) : state 
} 

但是,COUNTER_DOUBLE動作處理程序似乎沒有更新視圖,也沒有任何呈現。我得到這樣的警告:

警告:無法道具類型:提供給Counterfunction 的無效道具counter,預計number

我意識到我已經定義了一個數字propType並且返回promise函數導致這個錯誤。我甚至試圖修改mapDispatchToProps來返回執行的promise函數無濟於事。我究竟做錯了什麼?

我在這裏搜索和達成的共識似乎是使用redux-thunk包裝承諾與立即執行的功能,但我很難得到這個工作。

任何幫助,將不勝感激!

回答

3

默認情況下,redux預期動作是普通對象。如果你想寫一些異步代碼並返回一個承諾,你需要使用某種中間件,redux-thunk將是一個不錯的選擇。

redux-thunk的README頁面實際上是相當有記錄的,並且有一個完整的示例。基本上你需要到了Redux-thunk的中間件應用到你的店是這樣的:

import { createStore, applyMiddleware } from 'redux'; 
import thunk from 'redux-thunk'; 
import rootReducer from './reducers'; 

const store = createStore(
    rootReducer, 
    applyMiddleware(thunk) 
); 

另外我建議你閱讀了Redux文檔中關於async action creators,它有一些很好的例子。

0

剛剛看到this commit在原來的回購正是這樣做。

這是改變:

export const doubleAsync =() => { 
    return (dispatch, getState) => { 
    return new Promise((resolve) => { 
     setTimeout(() => { 
     dispatch({ 
      type : COUNTER_DOUBLE_ASYNC, 
      payload : getState().counter 
     }) 
     resolve() 
     }, 200) 
    }) 
    } 
} 
+2

沒錯。訣竅是當承諾完成時觸發另一個行動。承諾不應該存儲在狀態。創建一箇中間件可以爲每個異步操作觸發3個動作 - 「掛起」,「成功」和「錯誤」,這很好。你甚至可以創建通用的reducers來存儲數據或錯誤。 – Sulthan