Общим вопросом для новичков в React является то, почему двусторонняя привязка данных не является встроенной функцией, а обычный ответ включает объяснение однонаправленного потока данных, а также идею о том, что привязка данных с двусторонней привязкой не всегда желательна по соображениям производительности, Это второй момент, который я хотел бы разобраться более подробно.
В настоящее время я работаю над библиотекой форм для apollo-link-state (новый клиентский инструмент управления государственными средствами от Apollo). Концепция очень похожа на редукционную форму, за исключением использования apollo-link-state вместо redux в качестве менеджера состояний. (Обратите внимание, что состояние формы хранится отдельно от состояния объектов домена, хотя объект может быть необязательно использован для заполнения начального состояния формы.)
Когда пользователь вносит изменения в форму, библиотека немедленно обновляет хранилище с помощью обработчиков onChange
. Я думал о том, чтобы позволить отдельным полям отказаться от этого поведения, если программист был обеспокоен производительностью, но потом я начал задаваться вопросом, когда это будет когда-либо реальная проблема с производительностью. Браузер будет oninput
событие oninput
несмотря ни на что, поэтому единственным соображением производительности, о котором я могу думать, является то, обновляется ли хранилище по типу пользователя. Конечно, есть дополнительные накладные расходы на выполнение мутации, а не просто вызов setState()
, но это, по сути, всего лишь пара дополнительных вызовов функций. И пусть предположим, что я не использовал apollo, а просто вызвал функцию, которая напрямую обновляет какой-то глобальный магазин, - каков будет анализ производительности?
Мое мышление заключается в том, что если форма будет поддерживать немедленное обновление состояния формы по мере того, как пользователь вводит в одном поле, он может также сделать это для всех полей. Пользователь может вводить только одно поле за раз, и я не вижу преимущества того, что страница иногда быстрее (возможно, незначительна) с некоторыми полями, а иногда и с другими. Кроме того, моя библиотека позволяет потребителям использовать любые входные компоненты, которые они хотят, поэтому, если программист просто хочет меньше обновлений состояния, они могут просто написать компонент, который onChange
событие React onChange
или вместо этого использует собственное change
или blur
браузера.
Я что-то упустил? Есть ли еще одна причина, по которой пользователь моей библиотеки хотел бы игнорировать изменения для определенных полей, пока пользователь не отправит форму? Или, может быть, более полезным вариантом было бы игнорировать изменения во всей форме (до отправки)?
Вот базовая (значительно упрощенная) иллюстрация базовой концепции моего текущего подхода:
// defined in a globally-accessible module
const formState = {
// This somehow causes any dependent form components to re-render
// when state changes
update(formName, updatedState) {
...
}
}
export default formState
...
// UserForm.js:
export default class UserForm extends PureComponent {
componentDidMount() {
formState.userForm = {
firstName: '',
lastName: '',
}
}
handleChange(e) {
const { target } = e
formState.update('userForm', { [target.name]: target.value })
}
//...
render() {
const { userForm } = formState
return (
<form onSubmit={this.handleSubmit}>
<label for="name">Name</label>
<input id="name" type="text" onChange={this.handleChange} value={userForm.name} />
<label for="email">Email</label>
<input id="email" type="email" onChange={this.handleChange} value={userForm.email} />
</form>
)
}
}
Наконец, для полноты, я должен упомянуть, что в этом есть некоторые аспекты проектирования API. Отдельные компоненты ввода могут иметь несколько более простой дизайн, если я не предоставил возможность отказаться от автоматической двусторонней привязки. Я могу опубликовать детали, если кому-то это интересно.