Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux form: REGISTER_FIELD / UNREGISTER_FIELD get called after change or focus events

I’m using Redux Form to render and handle form events in my React app. The following things are used:

  • Initial values
  • Field arrays
  • Immutable.js
  • Material UI

Also, the field arrays are build using the initial values.

export default connect(
  state => {
    return {
      buttonVisible,
      confirm,
      initialValues: Immutable.Map({
        configuration_items: configuration_items,
      })
    }
  }
)(AssetConfiguration)

The problem is that all the fields in the form get deregistered and registered on every change or focus event. Without the defaultValues, it seems to work fine though.

I’m using a React component to render the form, something like this

class ConfigurationForm extends React.Component {
  renderTableBody({ fields, meta: { touched, error } }) {
    return(
      <tbody>
        {fields.map((field, index) => {
          return(
            <tr key={index}>
              <td>
                <Field fieldIndex={index} name={`${field}.value`} id={`${field}.value`} component={this.renderItemField.bind(this)} />
              </td>
            </tr>
          )
        })}
      </tbody>
    )
  }

 render() {
    return (
      <form className="defaultForm" onSubmit={handleSubmit(postAssetConfiguration)}>
        <FieldArray name="configuration_items" component={this.renderTableBody.bind(this)} />
      </form>
    )
  }
}

What could be the problem here?

Thanks, Rens

like image 415
Rens Avatar asked Nov 07 '16 09:11

Rens


2 Answers

If anyone is still having issues, I had similar problem with FieldArray and my solution was to remove bind completely and put it in it's own component so that it doesn't re-render array. It has to be outside of the component that's rendering it -

const renderItemField = ({ input }) => {
  return (
    <div>
      <input {...input} />
    </div>
  );
};

const renderTableBody = ({ fields, meta: { touched, error } }) => {
  return(
    <tbody>
      {fields.map((field, index) => {
        return(
          <tr key={index}>
            <td>
              <Field fieldIndex={index} name={`${field}.value`} id={`${field}.value`} component={renderItemField} />
            </td>
          </tr>
        )
      })}
    </tbody>
  )
};

class ConfigurationForm extends React.Component {
  render() {
    return (
      <form className="defaultForm" onSubmit={handleSubmit(postAssetConfiguration)}>
        <FieldArray name="configuration_items" component={renderTableBody} />
      </form>
    )
  }
}
like image 73
grgmo Avatar answered Nov 15 '22 10:11

grgmo


I'm investigating a similar issue. My guess is: you are passing in this.renderTableBody.bind(this) and this.renderItemField.bind(this) as components. Every time render is called, these will be new references, triggering an unnecessary rerender. This is considered bad practice: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md

like image 23
Márton Borlay Avatar answered Nov 15 '22 08:11

Márton Borlay