使用 Redux 从 reducer 返回一个 promise

Returning a promise from a reducer with Redux

我正在使用 this starter kit and the code below can be found on this fork

计数器组件:

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 操作处理程序似乎没有更新视图,也没有呈现任何内容。我收到此警告:

Warning: Failed prop type: Invalid prop counter of type function supplied to Counter, expected number.

我意识到我已经定义了一个数字 propType 并且 return 承诺函数导致了这个错误。我什至尝试将执行的承诺功能修改 mapDispatchToProps 为 return 无济于事。我做错了什么?

我在这里搜索过,似乎一致认为使用 redux-thunk 将 promise 包装在一个立即执行的函数中,但我很难让它工作。

如有任何帮助,我们将不胜感激!

默认情况下,redux 期望动作是普通对象。如果您想编写一些异步代码和 return 承诺,您需要使用某种中间件,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)
);

此外,我建议您阅读有关 async action creators 的 redux 文档,其中有一些很好的示例。

刚刚在原始仓库中看到 this commit 正是这样做的。

这是变化:

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