【问题标题】:Redux-form handleSubmit: How to access store state?Redux-form handleSubmit:如何访问 store 状态?
【发布时间】:2016-09-29 02:32:53
【问题描述】:

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

如果我想在表单的组件中定义handleSubmit,这很容易:只需调用mapStateToProps 传递我需要的任何内容,然后从this.props 中的handleSubmit 中读取它。

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

再一次,很简单——redux-form 就是为了做到这一点而设置的。在mapDispatchToProps中定义一个onSubmit,表单会自动调用。

除了,哦,等等,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 将 state 属性复制到 redux-form 字段中,这些字段不会映射到表单组件中的任何输入控件。这将确保它们可以在传递回handleSubmitvalues 参数中访问。这似乎是一种 hack。

一定有更好的方法!

有没有更好的方法?

【问题讨论】:

    标签: reactjs redux react-redux redux-form


    【解决方案1】:

    在花时间细化这个问题之后,选项 #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]
    

    【讨论】:

    • 这仍然是最好的方法吗..?
    • 很好的问答,就像你读懂了我的想法。我想知道这种技术是否有特定的名称?这是咖喱的一个例子吗?您实际上是将二进制函数mySubmitHandler 包装在另一个一元函数中,即fn (a) { fn(a, b) },我认为它在技术上符合定义。只是好奇
    • @sbeam 这不是柯里化,但很接近。柯里化将声明一个函数const add = x =&gt; y =&gt; x + y,而这更像const add = x =&gt; myAdder(x, y)。我在下面提供了更详细的答案。
    【解决方案2】:

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

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

    动作创建者:

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

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

    组件

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

    这可以很容易地为无状态功能组件重写,只要将它们放在动作创建器的左侧,就可以处理任意数量的参数,并且不需要任何繁重的工作,只需 bind

    【讨论】:

      【解决方案3】:

      我可以通过绑定this来解决这个问题。

      在 render() 中的某处

      <MyCustomFormComponent onSubmit={handleSubmit.bind(this)}/>
      

      handleSumit

        handleSubmit(fields) {
          this.props.onSubmit(fields); //this is properly bound, HURRAY :-)
        }
      

      MapDispatchToProps 给优秀的开发者:-)

      const mapDispatchToProps = dispatch => ({
        onSubmit: (fields) =>
          dispatch({type: auth.actionTypes.LOGIN, payload: auth.api.login(fields)})
      });
      

      【讨论】:

      • 这个问题是关于在 mapDispatchToProps() 中访问存储状态的。看起来您的示例只是展示了如何使用 handleSubmit 的“普通”案例,您只需要从字段中访问数据(无需来自商店的任何其他数据)。为此,您可以按照 redux-form 文档中的说明进行操作。
      • 感谢您的回复。实际上,当我在 handleSubmit 中访问 thisOrg 时,我可以访问其中的存储状态,并且可以将任何内容传递给 MapDispatchToProps 的 onSubmit 方法。我已经检查以获得任何状态值(不仅仅是字段),并且它是成功的。对不起,如果我错过了什么或误解了你的问题。如果答案有误,我愿意更改/删除我的答案。
      • 嗯,问题是是否可以在mapDispatchToProps 中获取存储数据不将其传递到表单组件,因为它是表单不需要的数据并且没有业务知道。如果没有看到您的代码,我无法判断,但听起来您正在描述将数据传递到表单中(可能是通过mapStateToProps?您没有说),然后在handleSubmit 中再次将其传递回来。这样做已经包含在接受的答案中。如果您正在做一些不同的事情,您可以发布您的代码,如果它添加了尚未涵盖的信息。
      【解决方案4】:

      这是 @stoneanswer 的变体,但您可以通过函数式编程分解选项 1:

      const mySubmitHandler = props => values => { /* ...code here */ }
      
      <form onSubmit={ handleSubmit(mySubmitHandler(this.props)) }>
      

      在这种情况下,mySubmitHandler 将返回一个函数,该函数只接受一个已在 this.props 上关闭的参数,因此无需明确提及 handleSubmit 正在传递的 values 参数。

      您可以通过ramda 以更好、更易读的方式执行mySubmitHandler 的柯里化。

      import { curry } from 'ramda';
      
      const mySubmitHandler = curry((props, values) => { /* ...code here */ });
      

      你可以更进一步,组合handleSubmitmySubmitHandler

      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) 返回一个函数,该函数接受一个参数 (values) 并关闭了 this.props,创建了一个可以访问它需要的所有属性的函数!

      【讨论】:

        猜你喜欢
        • 2017-03-15
        • 2023-03-23
        • 2020-05-09
        • 2018-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-22
        • 1970-01-01
        相关资源
        最近更新 更多