Search code examples
javascriptreactjsreact-reduxreact-redux-form

redux form component not reflecting store state


I created a very simple yes / no component mapped to true / false values with redux form. When clicking "No" the value is updated in the store, but the component does not update. Only after clicking Yes first the component updates when clicking No.

What am I doing wrong here ? why is the state in the store not reflected in the component ?
Note that it's important for my use case that initially, no button is clicked.

sandbox:

https://codesandbox.io/s/r06VKjB4K

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

const buttonStyle = {
  width: '50px',
  display: 'inline-block',
  border: '1px solid green',
  margin: '5px',
  padding: '5px',
  cursor: 'pointer',
  textAlign: 'center',
};

const ButtonBar = ({ options, input }) =>
  <div style={{ display: 'block' }}>
    {options.map(x =>
      <div
        onClick={() => {
          input.onChange(x.value);
        }}
        style={{
          ...buttonStyle,
          ...{
            backgroundColor: input.value === x.value ? x.selected : 'white',
          },
        }}
      >
        {x.displayName}
      </div>,
    )}
  </div>;

const SimpleForm = props => {
  return (
    <form>
      <div style={{ display: 'inline-block', border: '1px solid grey' }}>
        <Field
          name="myButton"
          component={ButtonBar}
          options={[
            {
              value: true,
              displayName: 'Yes',
              selected: 'green',
            },
            {
              value: false,
              displayName: 'No',
              selected: 'red',
            },
          ]}
        />
      </div>
    </form>
  );
};

export default reduxForm({
  form: 'simple', // a unique identifier for this form
})(SimpleForm);

Solution

  • I think the reason is that somewhere in the redux-form code, it treats the empty string and false as the same thing initially and does not trigger a rerender. It looks like redux-form uses this deepEquals function customizer:

    const customizer = (obj, other) => {
      if (obj === other) return true
      if (
        (obj == null || obj === '' || obj === false) &&
        (other == null || other === '' || other === false)
      )
        return true
    
      if (obj && other && obj._error !== other._error) return false
      if (obj && other && obj._warning !== other._warning) return false
    }
    

    You could try setting the initial value to false yourself to see if it fixes your problem.