React Form контролируется Flux Store (лучшая практика?)

Итак, у меня есть большой компонент, который будет моей формой:

<form>
 <FirstComponent value={this.state.firstValue}/>
 <SecondComponent value={this.state.secondValue}/>
 {more components here}
 <input type="submit" ... />
</form>

Этот компонент формы прослушивает хранилище, которое обновляет свои значения, используя firstAction, secondAction и т. д.

Примечание. Компонент обновляет свое состояние на основе функции store.getState(), которая возвращает {firstValue: something, secondValue: something, etc}.

Итак, скажем, мой FirstComponent является вводом:

<input type="text" value={this.props.value} 
   onChange={(e)=>this.props.firstAction(e.target.value)}
</input>

Итак, onChange запускает свойство firstAction, которое на самом деле является действием Flux, которое обновит мой магазин и заставит форму повторно отображаться. Здесь у меня есть две хорошие вещи: когда пользователь отправляет форму, я могу проверить значение FirstComponent в своем магазине, а также контролировать все свое состояние из родительского компонента.

Однако этот обратный вызов onChange будет вызывать действие каждый раз, когда пользователь вводит один символ (поэтому он может производить много вызовов, следовательно, повторно отображать) ‹-- может ли это вызвать серьезные проблемы с производительностью?

Вместо этого я мог бы использовать refs, и когда пользователь нажмет кнопку отправки, получить this.refs.myFirstComponent.state... и у меня тоже будет значение (это будет Неуправляемый компонент?) Но это не похоже на рекомендацию сообщества.

Итак, мой вопрос: является ли первый подход, который я описал выше, хорошим способом? Как я могу оптимизировать его? Таким образом, повторный рендеринг, который должен влиять только на FirstComponent, не приводит к повторному рендерингу SecondComponent и так далее? shouldComponentUpdateединственный способ добраться сюда?


Редактировать 1:

При первом подходе у меня возникла проблема... У меня есть тест e2e с использованием WebdriverIO, добавляющий значение в текстовое поле: http://webdriver.io/api/action/setValue.html

Я не знаю почему, но если я попытаюсь добавить слово «Тестирование» во ввод, веб-драйвер добавит только последнюю букву. Эта проблема исчезнет, ​​если вообще не использовать состояние/хранилище. Однако, если у меня есть состояние внутри моего FirstComponent, что-то вроде:

<input type="text" value={this.state.value} 
   onChange={(e)=>this.setState({firstValue: e.target.value})}
   onBlur={()=>this.props.callback(this.state.firstValue)}
</input>

В этом случае кажется, что компонент быстрее реагирует при наборе текста (отрисовывает только себя), а затем, когда пользователь удаляет фокус, он обновляет хранилище. Я должен сказать, что мне не нравится этот подход, потому что он не следует шаблону подъема вашего состояния (и я чувствую, что дублирую состояние), НО кажется, что он работает быстрее и важнее: мой тест e2e работает. Есть еще идеи?


person Ferran Negre    schedule 30.07.2015    source источник


Ответы (1)


Ваш первый подход (т. е. onChange запускает потоковое действие, которое обновляет хранилище и делает повторную визуализацию вашей формы) кажется хорошим способом. Я использовал его таким образом, и я видел, как другие люди использовали его таким же образом.

По поводу вашего следующего комментария:

Однако этот обратный вызов onChange будет вызывать действие каждый раз, когда пользователь вводит один символ (поэтому он может производить много вызовов, следовательно, повторно отображать) ‹-- может ли это вызвать серьезные проблемы с производительностью?

Да, я так думаю. Однажды я создал компонент, который содержит множество других компонентов вместе с некоторыми полями ввода. Всякий раз, когда я вводил символ в поле ввода, весь компонент (с другими включенными в него компонентами и полями ввода) перерисовывался, вызывая проблемы с производительностью. Это было заметно, если я печатал быстро. Вы можете проверить это, используя https://facebook.github.io/react/docs/perf.html.

В любом случае, как я обошел проблему, как вы упомянули, реализовав shouldComponentUpdate().

Небольшой совет, который я хотел бы упомянуть, — это создание пользовательского компонента <Input />, который охватывает <input />, и реализация shouldComponentUpdate() (то есть this.props.value !== nextProps.value || this.props.checked !== nextProps.checked). Таким образом, если вы создаете компонент формы, например, со многими полями ввода (используя пользовательский <Input />), повторно отображается только измененное поле ввода.

Хотя хотелось бы посмотреть, как другие люди подходят к этой проблеме.

person Brian Park    schedule 31.07.2015
comment
Проверьте мой Edit 1, используя подход действия, я столкнулся с проблемой в своих тестах e2e... - person Ferran Negre; 31.07.2015
comment
Почему это может вызвать проблемы с производительностью? Я думал, что виртуальный DOM React обрабатывает такие проверки внутри и отображает только то, что изменилось. Это примечательная особенность React, когда речь идет о производительности. Я ошибаюсь? - person Alex; 27.06.2017