3
votes

I'm working to build the redux-form below to collect emails as user input. The fields should all have the same name="email"

The problem is when the component renders, and I focus and type in one field, all the fields instantly update with the latest value from the first input field. All three of the fields seem to be tied together.

With redux-form, how do I enable the form to have inputs with the same name?

import React from 'react';
import { Field, reduxForm } from 'redux-form';
import {connect} from 'react-redux';

class InvitePage extends React.Component {

  handleSubmit(data) {
    console.log(data)
  }

  render() {

    return (
      <div>
        <h1>Invites</h1>
          <form onSubmit={this.props.handleSubmit(this.handleSubmit.bind(this))}>
            <div>
              <label>Email address</label>
              <div>
                <Field
                  name="email"
                  component="input"
                  type="email"
                  placeholder="Email"
                />
              </div>
              <div>
                <Field
                  name="email"
                  component="input"
                  type="email"
                  placeholder="Email"
                />
              </div>
              <div>
                <Field
                  name="email"
                  component="input"
                  type="email"
                  placeholder="Email"
                />
              </div>
            </div>

            <div>
              <button type="submit">Submit</button>
            </div>

          </form>
      </div>
    );
  }

}

InvitePage = reduxForm({
  form: 'InvitePage'
})(InvitePage);

export default InvitePage;
1
If they are all taking email as an input, why do you have three fields? - VivekN
so a user can input 1 or more emails. - AnApprentice
Then change the names to email and email - 1. Giving them the same name will create confusion. I am assuming that redux form here would be identifying a field as unique with its name which is why you are facing this issue. Just name them differently. - VivekN
I think that's the point of the ID attribute, I don't believe that should be a requirement for the name attribute. - AnApprentice
By reading the redux form createField function, it appears that they are relying on the name field to register a field with them. Check componentWillMount function here github.com/erikras/redux-form/blob/master/src/createField.js - VivekN

1 Answers

6
votes

If you use a FieldArray instead of 3 Fields, it can handle generating a unique name in redux-form's state for each field and you can use a renderer which hardcodes (or allows you to override) the name field to whatever you want, as redux-form generates an onChange handler for each field which updates the correct piece of state regardless of what you render for the name attribute.

Here's an example which shows that in action:

Relevant code snippet:

// For the sake of this example, we're hard-coding the name to 'email'
let renderEmailField = ({input, label, type, meta: {touched, error}}) =>
  <div>
    <label>{label}</label>
    <div>
      <input {...input} name="email" type="email"/>
      {touched && error && <span>{error}</span>}
    </div>
  </div>

let renderEmails = ({fields, meta: {submitFailed, error}}) =>
  <ul>
    <li>
      <button type="button" onClick={() => fields.push()}>Add Email</button>
    </li>
    {fields.map((email, index) =>
      <li key={index}>
        {index > 2 && <button
          type="button"
          title="Remove Email"
          onClick={() => fields.remove(index)}
        />}
        <Field
          name={email}
          component={renderEmailField}
          label={`Email #${index + 1}`}
        />
      </li>
    )}
    {submitFailed && error && <li className="error">{error}</li>}
  </ul>

let EmailsForm = ({handleSubmit, pristine, reset, submitting}) =>
  <form onSubmit={handleSubmit}>
    <FieldArray name="emails" component={renderEmails} />
    <div>
      <button type="submit" disabled={submitting}>Submit</button>
      <button type="button" disabled={pristine || submitting} onClick={reset}>
        Clear Values
      </button>
    </div>
  </form>

EmailsForm = reduxForm({
  form: 'emailsForm',
  // Provide 3 initial values to show 3 email fields
  initialValues: {
    emails: ['', '', '']
  }
})