React:动作创建者不调用reducer

时间:2015-11-19 16:29:21

标签: javascript reactjs redux

我正在我的动作创建者中进行异步调用并使用结果调用我的reducer,但由于某种原因我无法理解减速器没有被调用。

actions.js(行动和行动创造者)

export const GET_FORMS = 'GET_FORMS'

export function getForms() {
  $.get("server url", function(result) {
   return {
    type: GET_FORMS,
    formlist: result.data.forms
   }   
  })
 }

reducers.js

import { GET_FORMS } from '../actions/actions'

export default function formAction(state = {forms:[]}, action) {
  console.log("received action"+action.type)
  switch (action.type) {

    case GET_FORMS:
      console.log("Action:"+action);
      return Object.assign({},state,{
       forms:action.formlist
      })

   default:
    return state
 }
}

App.js

import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom';
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import auth from '../auth'
import FormTable from '../components/FormTable'
import * as FormActions from '../actions/actions'


class App extends Component {

 constructor(props) {
  super(props);
  this.state = {forms: []};
 }

 componentDidMount() {
  // for some reason if i write this.props.actions.getForms () i get an error
  // Uncaught Error: Actions must be plain objects. Use custom middleware for 
  // async actions.
  FormActions.getForms();
 }

 render() {
  const {forms,actions} = this.props
  console.log(forms);
  return (
    <FormTable results={forms} actions = {actions} /> 
  )
 }
}

App.PropTypes = {
  forms: PropTypes.array.isRequired
}

function mapStateToProps() {
 const {
  forms:forms
 } = {forms:[]}

 return {
  forms
 }
}

function mapDispatchToProps(dispatch) {
 return {
  actions: bindActionCreators(FormActions, dispatch)
 }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App)

2 个答案:

答案 0 :(得分:12)

这里有一些事情。

  1. 您的动作创建者不会返回正在创建的动作。 $.get不会返回操作,因此将其映射到dispatch效率不高。

    合理地说,这可能会导致对如何从异步操作创建者返回操作感到困惑。由于它是异步的,因此它无法返回最终结果(除非您使用的是es7 async await)。您尝试的模式与此相同:

    class App extends Component {
      ...
      componentDidMount() {
        // Instead of calling getForms, do the same directly
        $.get(url, function(res) {
          return { type: GET_FORMS, forms: res };
        });
      }
    
      render() { ... }
    }
    

    $.get api我们知道$.get会返回jqXHR object ,不是任何行动。所以你必须在自己的回调中使用结果 - 你不能只返回它。以下是componentDidMount的示例(注意回调绑定到this):

    componentDidMount() {
      $.get(url, function(res) {
        this.props.dispatch({ type: GET_FORMS, forms: res });
      }.bind(this))
    }
    
  2. 在您的组件或动作创建者中执行异步是一种反模式,或至少是不鼓励的。在这种情况下,您在动作创建者中定义异步,这很棒。但你也在执行异步操作,这很糟糕。相反,您应该使用某种中间件来处理异步操作。中间件只是在发送后采取行动并对其进行处理的功能,而最常见的功能是redux-thunk。使用redux-thunk,您只需返回一个接受dispatch作为参数的函数。在这种情况下,您的动作创建者将如下所示:

    export function getForms() {
      return function(dispatch) {
        $.get(url, function(result) {
          dispatch({ type: GET_FORMS, forms: result });
        })
      }
    }
    

    这与你正在做的非常相似,除了你正在创建一个thunk - 这只是一个定义另一个函数以便稍后执行的函数 - 而不是实际执行异步操作现在,您将其定义为稍后执行。

  3. 你实际上并没有派遣任何东西。

    要修复的最简单的问题,但绝对是障碍:)在componentDidMount中,您正在调用已导入的动作创建者,但您没有调用dispatch。虽然你已经将动作创建者传递给了connect,但是你已经有50%了,但即使你这样做了,你也没有调用connect传递给道具的绑定动作创建者 - 你称之为未绑定的人。

    因此,您需要致电FormActions.getForms(),而不是致电this.props.actions.formActions()。前者不受约束,后者则受约束。调用后者与执行this.props.dispatch(FormActions.getForms())相同。

  4. 最后:在这种情况下,您无需定义mapDispatchToProps。您可以将对象传递给connect的参数。见下文:

    // Instead of this
    export default connect(mapStateToProps, mapDispatchToProps)(App);
    
    // do this:
    export default connect(mapStateToProps, FormActions)(App);
    // creates the bound action creator 'this.props.getForms()'
    

    这个主要是样式选择,但我认为这是一个很好的模式:)对于多个动作创建者源对象,你可以这样做:

    export default connect(mapStateToProps, { ...FormActions, ...UserActions })(App);
    

答案 1 :(得分:4)

你应该使用redux-thunk中间件: https://github.com/gaearon/redux-thunk

基本上就像你的代码所代表的那样 - 你没有返回符合FSA的行动(实际上现在没有返回任何东西)。你需要重新发送调度,然后返回承诺的结果。

有关异步操作创建者的更多信息,请访问:http://redux.js.org/docs/advanced/AsyncActions.html