React:动作创建者不调用减速器
React : Action creator not calling reducer
我正在我的 action creator 中进行异步调用,并用结果调用我的 reducer,但出于某种原因,我无法理解没有调用 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)
你应该使用 redux-thunk 中间件:
https://github.com/gaearon/redux-thunk
基本上就您的代码而言 - 您没有 return 执行符合 FSA 的操作(实际上现在没有 return 执行任何操作)。您需要对调度进行 thunk,然后 return 承诺的结果。
这里有更多关于异步操作创建者的信息:http://redux.js.org/docs/advanced/AsyncActions.html
这里有一些东西。
您的动作创建器不会 return 它正在创建的动作。 $.get
没有 return 一个动作,因此将它映射到 dispatch
是没有效率的。
合理地,这可能会导致对如何 return 来自异步动作创建者的动作感到困惑。由于它是异步的,本质上它不能 return 最终结果(除非你使用的是 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
return 是 jqXHR
object
,而不是任何一种行动。所以你必须在回调中使用它自己的结果——你不能只 return 它。下面是 componentDidMount
的示例(注意回调绑定到 this
):
componentDidMount() {
$.get(url, function(res) {
this.props.dispatch({ type: GET_FORMS, forms: res });
}.bind(this))
}
在您的组件或动作创建器中执行异步是一种反模式,或者至少是不鼓励的。在这种情况下,您正在 定义 动作创建器中的异步,这很棒。但是您也在 执行 异步操作,这很糟糕。相反,您应该使用某种中间件来处理异步操作。中间件只是在它们被分派后采取行动并对其进行处理的功能,最常见的用于此目的的是 redux-thunk
。使用 redux-thunk
,您只需 return 一个接受 dispatch
作为参数的函数。在这种情况下,您的动作创建器将如下所示:
export function getForms() {
return function(dispatch) {
$.get(url, function(result) {
dispatch({ type: GET_FORMS, forms: result });
})
}
}
这与您已经在做的非常相似,只是您正在创建一个 thunk
——它只是一个定义另一个函数以供稍后执行的函数——而不是实际执行异步操作现在,您正在定义它以供稍后执行。
你实际上并没有发送任何东西。
要解决的最简单的问题,但绝对是一个障碍 :) 在 componentDidMount
中,您正在调用已导入的动作创建器,但没有调用 dispatch
。你已经完成了 50%,因为你将动作创建者传递给 connect
,但即使你这样做了,你也没有调用 connect
传递给 prop 的绑定动作创建者--你叫未绑定的。
因此,您需要调用 this.props.actions.formActions()
,而不是调用 FormActions.getForms()
。前者不受约束,但后者受约束。调用后者与 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);
我正在我的 action creator 中进行异步调用,并用结果调用我的 reducer,但出于某种原因,我无法理解没有调用 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)
你应该使用 redux-thunk 中间件: https://github.com/gaearon/redux-thunk
基本上就您的代码而言 - 您没有 return 执行符合 FSA 的操作(实际上现在没有 return 执行任何操作)。您需要对调度进行 thunk,然后 return 承诺的结果。
这里有更多关于异步操作创建者的信息:http://redux.js.org/docs/advanced/AsyncActions.html
这里有一些东西。
您的动作创建器不会 return 它正在创建的动作。
$.get
没有 return 一个动作,因此将它映射到dispatch
是没有效率的。合理地,这可能会导致对如何 return 来自异步动作创建者的动作感到困惑。由于它是异步的,本质上它不能 return 最终结果(除非你使用的是 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
return 是jqXHR
object ,而不是任何一种行动。所以你必须在回调中使用它自己的结果——你不能只 return 它。下面是componentDidMount
的示例(注意回调绑定到this
):componentDidMount() { $.get(url, function(res) { this.props.dispatch({ type: GET_FORMS, forms: res }); }.bind(this)) }
在您的组件或动作创建器中执行异步是一种反模式,或者至少是不鼓励的。在这种情况下,您正在 定义 动作创建器中的异步,这很棒。但是您也在 执行 异步操作,这很糟糕。相反,您应该使用某种中间件来处理异步操作。中间件只是在它们被分派后采取行动并对其进行处理的功能,最常见的用于此目的的是
redux-thunk
。使用redux-thunk
,您只需 return 一个接受dispatch
作为参数的函数。在这种情况下,您的动作创建器将如下所示:export function getForms() { return function(dispatch) { $.get(url, function(result) { dispatch({ type: GET_FORMS, forms: result }); }) } }
这与您已经在做的非常相似,只是您正在创建一个
thunk
——它只是一个定义另一个函数以供稍后执行的函数——而不是实际执行异步操作现在,您正在定义它以供稍后执行。你实际上并没有发送任何东西。
要解决的最简单的问题,但绝对是一个障碍 :) 在
componentDidMount
中,您正在调用已导入的动作创建器,但没有调用dispatch
。你已经完成了 50%,因为你将动作创建者传递给connect
,但即使你这样做了,你也没有调用connect
传递给 prop 的绑定动作创建者--你叫未绑定的。因此,您需要调用
this.props.actions.formActions()
,而不是调用FormActions.getForms()
。前者不受约束,但后者受约束。调用后者与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);