компонент формы редукса, не отражающий состояние хранилища

Я создал очень простой компонент да/нет, сопоставленный с истинными/ложными значениями с помощью избыточной формы. При нажатии "Нет" значение в магазине обновляется, но компонент не обновляется. Только после нажатия Да сначала компонент обновляется при нажатии Нет.

Что я здесь делаю неправильно? почему состояние в магазине не отражается в компоненте?
Обратите внимание, что для моего варианта использования важно, чтобы изначально не нажималась ни одна кнопка.

песочница:

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);

person Willem D'Haeseleer    schedule 14.06.2017    source источник
comment
Не можете ли вы сохранить это как input.value == x.value ?   -  person VivekN    schedule 14.06.2017
comment
@VivekN Нет, я указал в своем вопросе, почему бы и нет.   -  person Willem D'Haeseleer    schedule 14.06.2017
comment
Действительно, это связано со значениями true/false. Если вы замените их на a и b, все будет работать как положено. Я не очень хорошо знаком с редукционной формой, но документы могут объяснить это.   -  person enapupe    schedule 14.06.2017
comment
потому что ложное значение и при повторном нажатии кнопки «Нет» значение оказывается ложным, например, как оно изначально было пустой строкой, которую я предполагаю, что редукционная форма обрабатывает как ложную. Поскольку состояние не изменилось, поэтому нет повторного рендеринга .   -  person VivekN    schedule 15.06.2017
comment
@WillemD'Haeseleer вместо значений как истинных или ложных, можете ли вы сохранить их как что-то вроде Да или Нет   -  person VivekN    schedule 15.06.2017
comment
@VivekN Это неприемлемое решение.   -  person Willem D'Haeseleer    schedule 15.06.2017
comment
Пожалуйста, отправьте задачу со ссылкой на эту песочницу.   -  person Erik R.    schedule 15.06.2017
comment
@ЭрикР. github.com/erikras/redux-form/issues/3061   -  person Willem D'Haeseleer    schedule 15.06.2017


Ответы (3)


Я думаю, причина в том, что где-то в коде редукционной формы он изначально обрабатывает пустую строку и false как одно и то же и не запускает повторную визуализацию. Похоже, что redux-form использует этот настройщик функций deepEquals:

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
}

Вы можете попробовать установить начальное значение false самостоятельно, чтобы посмотреть, решит ли это вашу проблему.

person Stephen L    schedule 14.06.2017
comment
Принятие этого ответа, потому что он действительно указывает непосредственно на код, вызывающий ошибку в редукции-форме 6. Он будет исправлен в редукции-форме 7 (надеюсь -> github.com/erikras/redux-form/pull/3081) - person Willem D'Haeseleer; 20.06.2017

IDK точно, как работает редукционная форма, но у вас есть некоторые проблемы, связанные с неопределенным начальным состоянием и ложными значениями; Используя format, вы можете справиться с этим

https://codesandbox.io/s/BL50OzNZY

     format={(value) => value}

Просто возвращает значение, никаких дополнительных проверок не требуется.

person enapupe    schedule 14.06.2017
comment
Это очень любопытно, поскольку ваша функция буквально ничего не делает. Похоже, что действие по добавлению форматтера само по себе имеет побочный эффект решения проблемы. - person Willem D'Haeseleer; 15.06.2017
comment
Правильно. В этом ЕСЛИ нет необходимости, просто возврат самого значения отменяет некоторые другие проверки, исключающие ваше ложное значение. - person enapupe; 15.06.2017
comment
хорошо, это работает, но теперь каждый, кто использует мой компонент, должен будет включить таинственный форматтер, который ничего не делает. Не приятное решение. - person Willem D'Haeseleer; 15.06.2017

Это происходит потому, что ваше поле «myButton» имеет начальное состояние, равное «», и когда вы нажимаете кнопку «Нет», состояние меняется на false, но поскольку новое состояние равно предыдущему («» == false), компонент не перерисовывается.

Вы можете решить эту проблему, передав некоторое начальное состояние для вашего компонента, которое отличается от ваших параметров (true и false). Например, вы можете установить начальное состояние как любую строку:

<SimpleForm
    initialValues={{ myButton: 'notTrueOrFalse' }}
    onSubmit={showResults}
  />

https://codesandbox.io/s/0R1rw63nV

person Volodymyr Synytskyi    schedule 14.06.2017
comment
Это инициализировало хранилище с помощью notTrueOrFalse, что, я считаю, не идеально. - person enapupe; 15.06.2017
comment
Я ценю, что это работает, но это не похоже на очень хорошее решение. В дополнение к инициализации формы, после отправки формы мне придется добавить дополнительную логику, чтобы удалить это бесполезное значение. Я просто хочу сохранить логическое значение. - person Willem D'Haeseleer; 15.06.2017
comment
@WillemD'Haeseleer Я считаю, что вам уже нужно добавить дополнительную логику, потому что ваш компонент может дать вам три возможных значения: true, false, . Возможно, имеет смысл установить начальное значение компонента как true или false по умолчанию. - person Volodymyr Synytskyi; 15.06.2017
comment
Начальное состояние компонента должно быть невыбранным. Значение может быть истинным, ложным или неопределенным, три различных значения да. Я также открыт для решений, в которых третье состояние равно null или, в худшем случае, пустой строке. Но никаких других значений. - person Willem D'Haeseleer; 15.06.2017