如何将 redux-form 绑定连接到表单的输入

Posted

技术标签:

【中文标题】如何将 redux-form 绑定连接到表单的输入【英文标题】:How to wire up redux-form bindings to the form's inputs 【发布时间】:2016-01-13 07:28:15 【问题描述】:

redux-form 是一个非常引人注目的库,用于为 react 应用程序中的表单提供 redux 绑定,它应该非常方便。不幸的是,使用库自己的示例,我无法实际绑定任何东西,这非常不方便。

我试图利用项目站点上的示例代码,并发现了多个障碍,尽管我试图忠实地复制它。我在哪里误解了这个 API?自编写演示代码以来,API 是否发生了变化?我是否遗漏了一些重要且明显的 redux 知识?

问题1:handleSubmit 方法的签名应该是handleSubmit(data)。但是 handleSubmit 目前只接收来自提交动作的 React 合成事件,没有数据。 (实际上,使用编写的示例发送两个单独的事件,似乎是因为表单上堆叠的onSubmit 操作和按钮上的onClick。)该数据应该来自哪里,以及为什么我没有将它传递给处理程序吗?

问题 2:有一个关键的 fields 对象,必须在父表单上定义并作为道具提供给您的表单。不幸的是,文档中没有解释该fields 对象的形状,也没有真正解释它的用途。它本质上是初始的“状态”对象吗?一个简单的 redux-form 对象容器在运行时用于错误等?我已经通过将fields 上的道具与connectReduxForm 中的字段名称进行匹配来停止出错,但由于数据没有绑定,我假设它的形状不正确。

问题 3:这些字段应该自动绑定到 onBluronChange 的处理程序,以便它们适当地更新存储。那永远不会发生。 (感谢 Redux 开发工具,我们可以看到。但是,handleSubmit 正在成功调度 initialize 操作,这表明 store、reducer 和其他基本管道都在工作。)

问题 4validateContact 在初始化时会触发一次,但不会再次触发。

不幸的是,这对于一个简单的 Fiddle 来说太复杂了,但是整个 repo(它只是基本的 ReduxStarterApp,加上这个表单 POC)is available here。

而且,这里是外部组件:

import React       from 'react';
import  connect  from 'react-redux';
import initialize from 'redux-form';

import ContactForm from '../components/simple-form/SimpleForm.js';

const mapStateToProps = (state) => (
  counter : state.counter
);
export class HomeView extends React.Component 
  static propTypes = 
    dispatch : React.PropTypes.func.isRequired,
    counter  : React.PropTypes.number
  

  constructor () 
    super();
  
  handleSubmit(event, data) 
    event.preventDefault();
    console.log(event); // this should be the data, but is an event
    console.log(data); // no data here, either...
    console.log('Submission received!', data);
    this.props.dispatch(initialize('contact', )); // clear form: THIS works
    return false;
  

  _increment () 
    this.props.dispatch( type : 'COUNTER_INCREMENT' );
  


  render () 
    const fields = 
      name: '',
      address: '',
      phone: ''
    ;

    return (
      <div className='container text-center'>
        <h1>Welcome to the React Redux Starter Kit</h1>
        <h2>Sample Counter: this.props.counter</h2>
        <button className='btn btn-default'
                onClick=::this._increment>
          Increment
        </button>
        <ContactForm handleSubmit=this.handleSubmit.bind(this) fields=fields />
      </div>
    );
  


export default connect(mapStateToProps)(HomeView);

以及内部表单组件:

import React, Component, PropTypes from 'react';
import connectReduxForm from 'redux-form';

function validateContact(data) 
  console.log("validating");
  console.log(data);
  const errors = ;
  if (!data.name) 
    errors.name = 'Required';
  
  if (data.address && data.address.length > 50) 
    errors.address = 'Must be fewer than 50 characters';
  
  if (!data.phone) 
    errors.phone = 'Required';
   else if (!/\d3-\d3-\d4/.test(data.phone)) 
    errors.phone = 'Phone must match the form "999-999-9999"';
  
  return errors;


class ContactForm extends Component 
  static propTypes = 
    fields: PropTypes.object.isRequired,
    handleSubmit: PropTypes.func.isRequired
  

  render() 
    const  fields: name, address, phone, handleSubmit  = this.props;
    return (
      <form onSubmit=handleSubmit>
        <label>Name</label>
        <input type="text" ...name/>     /* will pass value, onBlur and onChange */
        name.error && name.touched && <div>name.error</div>

        <label>Address</label>
        <input type="text" ...address/>  /* will pass value, onBlur and onChange*/
        address.error && address.touched && <div>address.error</div>

        <label>Phone</label>
        <input type="text" ...phone/>    /* will pass value, onBlur and onChange */
        phone.error && phone.touched && <div>phone.error</div>

        <button type='submit'>Submit</button>
      </form>
    );
  


// apply connectReduxForm() and include synchronous validation
ContactForm = connectReduxForm(
  form: 'contact',                      // the name of your form and the key to
                                        // where your form's state will be mounted
  fields: ['name', 'address', 'phone'], // a list of all your fields in your form
  validate: validateContact             // a synchronous validation function
)(ContactForm);

// export the wrapped component
export default ContactForm;

【问题讨论】:

感谢您提出这个详尽的问题!我遇到了同样的困难,我发现 redux-form 文档和示例错综复杂且不完整。在您和@Jonny Buchanan 的帮助下,我得以继续进行(尽管我有一个复杂的数据结构而且我还没有完成)。添加redux devtools extension 对调试也有很大帮助! 【参考方案1】:

感谢 Jonny Buchanan,他涵盖了最重要的一点:不要像我那样做,并自动假设如果您的组件中需要 props,则您必须自己提供它们。高阶函数connectReduxForm 的全部意义在于在包装组件中提供它们。修复它立即给了我事件处理程序,除了提交之外的所有内容。

另一个重要的疏忽在这里:

注意——如果你不是自己做连接()(而且它是 建议您不要这样做,除非您有一个高级用例 需要它),您必须将减速器安装在 form

我没有抓住重点。但是,实现在这里:

import  createStore, combineReducers  from 'redux';
import  reducer as formReducer  from 'redux-form';
const reducers = 
  // ... your other reducers here ...
  form: formReducer           // <---- Mounted at 'form'

const reducer = combineReducers(reducers);
const store = createStore(reducer);

不能在formReducer 引用formReducer,但需要语法form: formReducer。这是正确启用handleSubmit 的更正。

【讨论】:

【参考方案2】:

connectReduxForm 将您的组件与另一个组件包装在一起,该组件处理传递 fieldshandleSubmit 道具,但是您通过自己传递它们将它们吹走。

试试这个(将道具重命名为onSubmit):

<ContactForm onSubmit=this.handleSubmit.bind(this)/>

ContactForm,pass your own submit handler to the handleSubmit function provided by redux-form:

<form onSubmit=handleSubmit(this.props.onSubmit)>

我建议使用 React developer tools 来更好地了解正在发生的事情 - 你会看到 redux-form 如何包装你的组件和 passes it a whole bunch of props, as documented in its README。

【讨论】:

你能更新链接吗?现在所有链接都指向redux-formgithub主页。

以上是关于如何将 redux-form 绑定连接到表单的输入的主要内容,如果未能解决你的问题,请参考以下文章

如何清除表单中的某些字段 - Redux-Form

在新的 Angular 2 表单中将 NgModel 绑定到 FormControl

如何将绑定连接到(Winform)ComboBox 控件以从绑定源获取/设置控件中的选择?

可以将绑定变量连接到动态 SQL WHERE 子句以添加 AND 语句吗?

将 redux-form 库 initialValue 注入 <Field>

如何将 jQuery Datepicker 连接到我的 Ruby on Rails 表单?