Redux-form handleSubmit:如何访问存储状态?

时间:2016-05-31 07:35:31

标签: reactjs redux react-redux redux-form

在进行Ajax调用的redux-form handleSubmit函数中,Ajax中需要一些Redux状态的属性(例如用户ID)。

如果我想在表单组件中定义handleSubmit,这很容易:只需调用mapStateToProps即可传入我需要的内容,并从this.props中读取它在我的handleSubmit

但是,像一个优秀的React-Redux开发人员一样,我编写单独的视图组件和容器,因此我的视图组件可以很简单,几乎没有行为。因此,我想在我的容器中定义handleSubmit

同样,简单的 - redux-form被设置为这样做。在onSubmit中定义mapDispatchToProps,表单会自动调用它。

除了,等等,在mapDispatchToProps中无法访问redux状态。

好的,没问题,我只需将我需要的道具传递给handleSubmit以及表格值。

嗯,等等,使用这种机制不可能将任何数据传递到handleSubmit!您得到一个参数values,并且无法添加其他参数。

这留下了以下没有吸引力的替代方案(我可以验证1和2的工作原理):

1 在表单组件中定义一个提交处理程序,然后从那里调用我自己从mapDispatchToProps传入的自定义提交处理函数。这没关系,但要求我的组件知道来自redux状态的一些道具,这些道具不是显示表格所必需的。 (此问题并非redux-form独有。)

dumbSubmit(values)
{
  const { mySubmitHandler, user} = this.props;
  mySubmitHandler(values, user);
}

<form onSubmit={ handleSubmit(this.dumbSubmit.bind(this)) }>

或者,更简洁地说,这可以合并为一个箭头函数:

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}

然后为了使这个处理程序完全不可知,它可以将整个this.props传递回自定义处理程序:

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}

2 在mergeProps中定义onSubmit 而不是mapDispatchToProps,因此它可以访问stateProps。 Dan Abramov recommends against using mergeProps (for performance reasons),所以这似乎不是最理想的。

  function mergeProps(stateProps, dispatchProps, ownProps) {
  const { user } = stateProps.authReducer;
  const { dispatch } = dispatchProps;
  return {
    ...ownProps,
    ...dispatchProps,
    ...stateProps,
     onSubmit: (values) => {
       const { name, description } = values;
       const thing = new Thing(name, description, []);
       dispatch(createNewThing(thing, user.id));
     }
  }

3 将状态属性复制到redux-form字段,这些字段未映射到表单组件中的任何输入控件。这将确保在传递回values的{​​{1}}参数中可以访问它们。这看起来像是一种黑客攻击。

必须有更好的方法!

有更好的方法吗?

3 个答案:

答案 0 :(得分:13)

在最后一次迭代(将所有道具传递回自定义处理程序的箭头函数)中花费时间完善此问题之后,选项#1实际上非常好。它允许组件无状态,并且完全不知道它不消耗的任何状态。所以我打算称这是一个合理的答案。我很乐意听到您更好的解决方案!

使用表单组件中的箭头函数定义提交处理程序,并从那里调用我自己从mapDispatchToProps传入的自定义提交处理函数。

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props.user);}

然后为了使这个处理程序完全不可知,将整个this.props传递回自定义处理程序:

<form onSubmit={ handleSubmit((values)=>{mySubmitHandler(values, this.props);}

如果Submit函数只需要不属于表单的值和道具,我们可以只传回表单不使用的那些道具。在无状态组件中,这可能如下所示:

const Thing_Create = ({ fields: {name, description}, 
    error, 
    handleSubmit, 
    mySubmitHandler, 
    submitting, 
    onCancel, 
    ...otherprops}) => {
return (
<div>
  <form onSubmit={ handleSubmit((values)=>{
    mySubmitHandler(values, otherprops);}) }>
[rest of form definition would go here]

答案 1 :(得分:2)

我发现的最佳方式与您提出的第一个解决方案非常相似。

利用redux-form传递的handleSubmit道具可以采用将用作onSubmit道具的函数,并使用部分应用程序传递您需要的任何其他参数这一事实onSubmit

行动创作者:

function updateUser(id, { name, lastname }) { ... }

假设组件获得onUpdateUser属性,只将参数直接传递给动作创建者。该组件还获得user,这是一个具有id属性的对象,我们希望将这些属性与字段中的值一起传递给操作创建者。

组件

<form onSubmit={this.props.handleSubmit(this.props.onUpdateUser.bind(null, this.props.user.id))}>

这可以轻松地为无状态功能组件重写,只要您将它们放在动作创建器的左侧,就可以适用于任何数量的参数,并且它不需要任何繁重的工作,只需{ {1}}

答案 2 :(得分:1)

这是@stoneanswer的一种变体,但是您可以通过功能编程来分解选项1:

const mySubmitHandler = props => values => { /* ...code here */ }

<form onSubmit={ handleSubmit(mySubmitHandler(this.props)) }>

在这种情况下,mySubmitHandler将返回仅包含一个已在this.props上关闭的参数的函数,因此无需明确提及{{1} }正在传递。

您可以通过ramda以更好和更易读的方式执行values的计算。

handleSubmit

您可以通过组成mySubmitHandlerimport { curry } from 'ramda'; const mySubmitHandler = curry((props, values) => { /* ...code here */ });

来更进一步
handleSubmit

请注意,mySubmitHandler返回一个带有一个参数(import { compose, curry } from 'ramda'; const handleSubmit = values => { /* ...code here */ }; const mySubmitHandler = curry((props, values) => { /* ...code here */ }); const onSubmit = compose(handleSubmit, mySubmitHandler); <form onSubmit={ onSubmit(this.props) }> )并已在onSubmit(this.props)上关闭的函数,从而创建了一个可以访问其所需所有属性的函数!