代码之家  ›  专栏  ›  技术社区  ›  Boris K

提交Redux表单

  •  4
  • Boris K  · 技术社区  · 8 年前

    我有一个Redux表单,作为向导,我试图将其分解为几个子组件,如下所示: https://redux-form.com/7.0.4/examples/wizard/

    然而,为了提交表单数据,我无法将表单正确地连接到我的操作中。这个例子实际上是将onSubmit方法从路由器传递到表单中,我不想这样做;相反,我希望将表单连接到操作,然后将signUpUser方法传递到组成向导的三个组件中的最后一个。我目前的尝试是抛出两个错误:

    Uncaught TypeError: handleSubmit is not a function
    
    Warning: Failed prop type: The prop `onSubmit` is marked as required in `SignUp`, but its value is `undefined`.
    

    我原来的表单组件运行良好,但相同的逻辑在新组件中不起作用。我认为这是一个范围界定的问题,但不确定。我对React和Redux表单比较陌生,所以我发现这很难理解。思想?

    新(损坏)组件:

    import React, { Component, PropTypes } from 'react';
    import { connect } from 'react-redux';
    import * as actions from '../../actions';
    import SignupFirstPage from './signupComponents/signupFirstPage';
    import SignupSecondPage from './signupComponents/signupSecondPage';
    import SignupThirdPage from './signupComponents/SignupThirdPage';
    
    class SignUp extends Component {
        constructor(props) {
            super(props);
            this.nextPage = this.nextPage.bind(this);
            this.previousPage = this.previousPage.bind(this);
            this.state = {
                page: 1
            };
            this.handleFormSubmit = this.handleFormSubmit.bind(this);
        }
        nextPage() {
            this.setState({ page: this.state.page + 1 });
        }
    
        previousPage() {
            this.setState({ page: this.state.page - 1 });
        }
    
        handleFormSubmit(props) {
            this.props.signUpUser(props);
        }
    
        render() {
            const { handleSubmit } = this.props;
            const { page } = this.state;
            return (
                <div>
                    {page === 1 && <SignupFirstPage onSubmit={this.nextPage} />}
                    {page === 2 && (
                        <SignupSecondPage
                            previousPage={this.previousPage}
                            onSubmit={this.nextPage}
                        />
                    )}
                    {page === 3 && (
                        <SignupThirdPage
                            previousPage={this.previousPage}
                            onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}
                        />
                    )}
                    <div>
                        {this.props.errorMessage &&
                            this.props.errorMessage.signup && (
                                <div className="error-container">
                                    Oops! {this.props.errorMessage.signup}
                                </div>
                            )}
                    </div>
                </div>
            );
        }
    }
    
    function mapStateToProps(state) {
        return {
            errorMessage: state.auth.error
        };
    }
    
    SignUp.propTypes = {
        onSubmit: PropTypes.func.isRequired
    };
    export default connect(mapStateToProps, actions)(SignUp);
    

    新的子组件(最后一个):

    import React from 'react';
    import { Field, reduxForm } from 'redux-form';
    import validate from './validate';
    import renderField from '../../renderField';
    
    const SignupThirdPage = props => {
        const { handleSubmit, pristine, previousPage, submitting } = props;
        return (
            <form onSubmit={handleSubmit}>
                <Field
                    name="password"
                    type="password"
                    component={renderField}
                    label="Password"
                />
                <Field
                    name="passwordConfirm"
                    type="text"
                    component={renderField}
                    label="Confirm Password"
                />
                <div>
                    <button
                        type="button"
                        className="previous btn btn-primary"
                        onClick={previousPage}>
                        Previous
                    </button>
                    <button
                        className="btn btn-primary"
                        type="submit"
                        disabled={pristine || submitting}>
                        Submit
                    </button>
                </div>
            </form>
        );
    };
    export default reduxForm({
        form: 'wizard', //Form name is same
        destroyOnUnmount: false,
        forceUnregisterOnUnmount: true,
        validate
    })(SignupThirdPage);
    

    import React, { Component } from 'react'
    import { connect } from 'react-redux'
    import { Field, reduxForm } from 'redux-form'
    import * as actions from '../../actions'
    import { Link } from 'react-router';
    
    const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
        <fieldset className="form-group">
            <label htmlFor={input.name}>{label}</label>
            <input className="form-control" {...input} type={type} />
            {touched && error && <span className="text-danger">{error}</span>}
        </fieldset>
    )
    
    class SignUp extends Component {
    
        constructor(props)
        {
            super(props);
    
            this.handleFormSubmit = this.handleFormSubmit.bind(this);
        }
    
        handleFormSubmit(props) {
            // Sign user up
            this.props.signUpUser(props);
        }
    
        render() {
            const { handleSubmit } = this.props;
    
            return (
                <div className="form-container">
                    <form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
                        <Field name="firstName" component={renderField} type="text" label="First Name" />
                        <Field name="lastName" component={renderField} type="text" label="Last name" />
                        <Field name="email" component={renderField} type="email" label="Email" />
                        <Field name="company" component={renderField} type="text" label="Company"/>
                        <Field name="password" component={renderField} type="password" label="Password" />
                        <Field name="password_confirmation" component={renderField} type="password" label="Password Confirmation" />
                        <div>
                            {this.props.errorMessage && this.props.errorMessage.signup &&
                                <div className="error-container">Oops! {this.props.errorMessage.signup}</div>}
                        </div>
                        <button type="submit" className="btn btn-primary">Sign Up</button>
                    </form>
                </div>
            );
        }
    }
    
    function validate(values) {
        let errors = {}
    
        if (values.password !== values.password_confirmation) {
            errors.password = 'Password and password confirmation don\'t match!'
        }
    
        return errors
    }
    
    function mapStateToProps(state) {
        return {
            errorMessage: state.auth.error
        }
    }
    
    SignUp = reduxForm({ form: 'signup', validate })(SignUp);
    export default connect(mapStateToProps, actions)(SignUp);
    
    2 回复  |  直到 8 年前
        1
  •  2
  •   Boris K    8 年前

    答案是:

    Redux表单上显示:

    由redux表单实例API提供的属性。

    它是这样工作的:因为我的组件是连接的,所以我可以在它的道具中访问我的动作。因此,在我的渲染方法中,我可以简单地将signUpUser方法传递到子组件中,如下所示:

    <SignupThirdPage
        previousPage={this.previousPage}
        signingUp={this.signingUp}
        onSubmit={values => this.props.signUpUser(values)}
    />
    
        2
  •  1
  •   Peter Catalin    7 年前

    你的问题是:

    {page === 3 && (
         <SignupThirdPage
           previousPage={this.previousPage}
           onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}
         />
    )}
    

    如果仔细查看代码,您会发现函数 handleSubmit 不存在。

    我想你是想写这个:

    <SignupThirdPage
      previousPage={this.previousPage}
      onSubmit={this.handleFormSubmit.bind(this)}
    />