2015-10-15 20 views
28

redux-form是一个非常引人注目的库,用于为反应应用程序中的表单提供redux绑定,这应该非常方便。不幸的是,使用图书馆自己的例子,我没有真正绑定任何东西,这是超方便的。如何将redux-form绑定连接到表单的输入

我试图利用项目网站上的示例代码,并发现多个障碍,尽管试图忠实地重现它。我在哪里误解了这个API?自从演示代码写入以来API已经移动了吗?我是否缺少一些关键和明显的重要知识?

问题1:handleSubmit方法的签名应该是handleSubmit(data)。但是handleSubmit目前只接收来自提交操作的React syntheticEvent,并且没有数据。 (事实上​​,使用写入的示例发送两个单独的事件,看起来是因为表单上的onSubmit堆栈操作和按钮上的onClick堆栈。)数据应该来自哪里,为什么我无法访问把它传递给处理程序?

问题2:有一个关键的fields对象必须在父窗体上定义并作为prop提供给窗体。不幸的是,这个对象的形状没有在文档中解释,也没有在其目的中解释。它基本上是最初的'状态'对象吗?用于redux-form的简单对象容器,以便在运行时用于错误等等?我已经通过将fields上的道具匹配到connectReduxForm中的字段名称来阻止错误,但由于数据不具有约束力,我假设它不是正确的形状。

问题3:各字段应该是自动结合到处理程序onBluronChange,以使它们适当地更新存储。这从来没有发生过。 (我们可以看到多亏了终极版开发工具然而,handleSubmit成功分派initialize行动,这表明实体店,减速机等基本的管道都在努力。)

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

这对一个简单的小提琴来说太复杂了,但是整个回购(它只是基本的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 (!/\d{3}-\d{3}-\d{4}/.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; 
+1

谢谢你这个精心制作的问题!我遇到同样的困难,我发现复杂形式的文档和例子错综复杂。在你和@Jonny Buchanan的帮助下,我能够继续进行(虽然我有一个复杂的数据结构,但我还没有完成)。添加[redux devtools扩展](https://github.com/zalmoxisus/redux-devtools-extension)也对调试有很大帮助! –

回答

23

connectReduxForm用它处理传入fieldshandleSubmit道具另一个组件包装的成分,但你通过将它们传入自己而将它们吹走。

,而不是尝试这种(改名道具onSubmit):

​​

而且在ContactFormpass 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-form composition in React developer tools

+2

你能更新链接吗?所有链接现在指向'redux-form' github主页。 – Mithril

8

多亏强尼·布坎南,谁涵盖了最重要的一点:不要做像我一样,并自动假设,如果在你的组件需要的道具,你必须要自己提供。高阶函数connectReduxForm的整个要点是在包装器组件中提供它们。修复,立即给我事件处理程序,除了提交的一切。

的其他重要监督在这里:

注意 - 如果不这样做的connect()荷兰国际集团自己(和它 建议你不这样做,除非你有一个先进的使用情况 要求它),则必须将减速机安装在的形式

我没有理解这一点。但是,执行是在这里:

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的更正。

相关问题