Search code examples
reactjsreact-reduxredux-form

How to use reduxForm() and connect() together for class component in react?


added reducer in reducer file

const reducers = {
  // ... other reducers here ...
  form: formReducer
};

I am using redux-form v 7.1.2 with react v 16 and using reduxForm()`` but there is alreadyconnect()` applied in this class, tried 2 approached to add both HOC in the same page but failed on both.

below is the relevant code of my files , please check and let me know what is missing ?

  1. Using named export

renderField.jsx

    import React from 'react';

    const renderField = ({ input, label, type, meta: { touched, error } }) => (
      <div>
        <label>{label}</label>
        <div>
          <input {...input} placeholder={label} type={type} />
          {touched && error && <span>{error}</span>}
        </div>
      </div>
    );

    export default renderField;

Register.jsx

import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import { renderField } from './renderField';

class RegisterPage extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            user: {
                firstName: ''
            },
            submitted: false
        };

        this.handleSubmit = this.handleSubmit.bind(this);
    }


    handleSubmit (values) {
        this.setState({ submitted: true });
        const { user } = this.state;
        const { dispatch } = this.props;
        dispatch(userActions.register(user));
    }

    render () {
        const { registering } = this.props;
        return (
            <div className="col-md-6 col-md-offset-3">
                <h2>Register</h2>
                <form onSubmit={this.handleSubmit} >
                    <div className="form-group">
                        <Field
                            name="firstName"
                            type="text"
                            label="First Name"
                            className="form-control"
                            component={renderField}
                        />
                    </div>
                    <div className="form-group">
                        <button type="submit" className="btn btn-primary" disabled={this.pristine} >Register</button>
                        { registering && <Loading /> }
                        <Link to="/login" className="btn btn-link">Cancel</Link>
                    </div>
                </form>
            </div>
        );
    }
}

below class definition , here is connect and reduxForm usage

RegisterPage = reduxForm({
    form: 'register',
    destroyOnUnmount: false
})(RegisterPage);

const connectedRegisterPage = connect(mapStateToProps)(RegisterPage);

export { connectedRegisterPage as RegisterPage };

App.jsx

import { RegisterPage } from '../RegisterPage';

<Route path="/register" component={RegisterPage} />

BUT this gives multiple warning in console

Failed prop type: The prop component is marked as required in Field, but its value is undefined. in Field (created by RegisterPage)

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in. Check the render method of ConnectedField.


  1. with default export

Register.jsx

RegisterPage = reduxForm({
    form: 'register'
})(RegisterPage);

const connectedRegisterPage = connect(mapStateToProps)(RegisterPage);

export { connectedRegisterPage as default };

App.jsx

import RegisterPage from '../RegisterPage';
console.log("RegisterPage", RegisterPage); // undefined 

this gives no warning but display blank page in the browser


Solution

  • You have exported renderField as a default and imported as a named import. Correct it and it should work fine

    import React from 'react';
    
        const renderField = ({ input, label, type, meta: { touched, error } }) => (
          <div>
            <label>{label}</label>
            <div>
              <input {...input} placeholder={label} type={type} />
              {touched && error && <span>{error}</span>}
            </div>
          </div>
        );
    
        export {renderField};