我正在我的动作创建者中进行异步调用并使用结果调用我的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)
答案 0 :(得分:12)
这里有一些事情。
您的动作创建者不会返回正在创建的动作。 $.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))
}
在您的组件或动作创建者中执行异步是一种反模式,或至少是不鼓励的。在这种情况下,您在动作创建者中定义异步,这很棒。但你也在执行异步操作,这很糟糕。相反,您应该使用某种中间件来处理异步操作。中间件只是在发送后采取行动并对其进行处理的功能,而最常见的功能是redux-thunk
。使用redux-thunk
,您只需返回一个接受dispatch
作为参数的函数。在这种情况下,您的动作创建者将如下所示:
export function getForms() {
return function(dispatch) {
$.get(url, function(result) {
dispatch({ type: GET_FORMS, forms: result });
})
}
}
这与你正在做的非常相似,除了你正在创建一个thunk
- 这只是一个定义另一个函数以便稍后执行的函数 - 而不是实际执行异步操作现在,您将其定义为稍后执行。
你实际上并没有派遣任何东西。
要修复的最简单的问题,但绝对是障碍:)在componentDidMount
中,您正在调用已导入的动作创建者,但您没有调用dispatch
。虽然你已经将动作创建者传递给了connect
,但是你已经有50%了,但即使你这样做了,你也没有调用connect
传递给道具的绑定动作创建者 - 你称之为未绑定的人。
因此,您需要致电FormActions.getForms()
,而不是致电this.props.actions.formActions()
。前者不受约束,后者则受约束。调用后者与执行this.props.dispatch(FormActions.getForms())
相同。
最后:在这种情况下,您无需定义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