Использовать состояние или refs в компонентах формы React.js?
Я начинаю с React.js и хочу сделать простую форму, но в документации я нашел два способа сделать это.
Первый использует ссылки:
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var author = React.findDOMNode(this.refs.author).value.trim();
var text = React.findDOMNode(this.refs.text).value.trim();
if (!text || !author) {
return;
}
// TODO: send request to the server
React.findDOMNode(this.refs.author).value = '';
React.findDOMNode(this.refs.text).value = '';
return;
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder="Your name" ref="author" />
<input type="text" placeholder="Say something..." ref="text" />
<input type="submit" value="Post" />
</form>
);
}
});
И второй использует состояние внутри компонента React:
var TodoTextInput = React.createClass({
getInitialState: function() {
return {
value: this.props.value || ''
};
},
render: function() /*object*/ {
return (
<input className={this.props.className}
id={this.props.id}
placeholder={this.props.placeholder}
onBlur={this._save}
value={this.state.value}
/>
);
},
_save: function() {
this.props.onSave(this.state.value);
this.setState({value: ''
});
});
Я не вижу плюсов и минусов двух альтернатив, если таковые существуют. Благодарю.
Ответы
Ответ 1
Краткая версия: избегать ссылок.
Они плохо подходят для ремонтопригодности и теряют большую простоту рендеринга модели WYSIWYG.
У вас есть форма. Вам нужно добавить кнопку, которая сбрасывает форму.
- рефов:
- манипулировать DOM
- render описывает, как выглядела форма 3 минуты назад.
- состояние
- SetState
- render описывает, как выглядит форма.
У вас есть поле номера CCV на входе и некоторые другие поля в приложении, которые являются числами. Теперь вам нужно обеспечить, чтобы пользователь вводил только числа.
- рефов:
- добавить обработчик onChange (не будем ли мы использовать refs, чтобы этого избежать?)
- манипулировать dom в onChange, если это не число
- состояние
- У вас уже есть обработчик onChange
- добавить инструкцию if, если она недействительна ничего не делает
- render вызывается только в том случае, если он будет производить другой результат
Эх, неважно, премьер-министр хочет, чтобы мы просто сделали красную коробку, если она недействительна.
- рефов:
- сделать onChange обработчик просто вызвать forceUpdate или что-то еще?
- сделать вывод вывода на основе... huh?
- Где мы получаем значение для проверки в рендере?
- вручную манипулировать элементом className dom свойство
- Я потерял
- переписать без ссылок?
- читать из dom в рендеринге, если мы монтируем в противном случае, допустим?
- состояние:
- удалить оператор if
- сделать рендеринг на основе this.state
Нам нужно вернуть управление родительскому элементу. Данные теперь находятся в реквизитах, и нам нужно реагировать на изменения.
- рефов:
- реализовать componentDidMount, componentWillUpdate и componentDidUpdate
- вручную разделить предыдущие реквизиты
- манипулировать dom с минимальным набором изменений
- эй! мы внедряем реакцию в реакции...
- там больше, но мои пальцы больно
- состояние:
-
sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js
Люди думают, что рефссы "легче", чем держать его в состоянии. Это может быть правдой в течение первых 20 минут, это не соответствует моему опыту после этого. Положите свое "я", чтобы сказать "Да, я сделаю это через 5 минут", а не "Конечно, я просто переписал несколько компонентов".
Ответ 2
Я видел, как несколько человек цитировали приведенный выше ответ в качестве причины "никогда не использовать ссылки", и я хочу высказать свое (а также несколько других разработчиков React, с которыми я говорил).
Мнение "не использовать ссылки" является правильным, когда речь идет об использовании их для экземпляров компонентов. Это означает, что вы не должны использовать ссылки как способ захвата экземпляров компонентов и вызова методов для них. Это неправильный способ использовать ссылки, и они быстро уходят на юг.
Правильный (и очень полезный) способ использования ссылок - это когда вы используете их для получения некоторого значения из DOM. Например, если у вас есть поле ввода, присоединяющее ссылку к этому входу, тогда захват значения позже через ссылку просто подойдет. Без этого вам придется пройти довольно организованный процесс для обновления поля ввода в соответствии с вашим локальным состоянием или хранилищем потоков - что кажется ненужным.
2019 редактировать: привет друзья будущего. В дополнение к тому, что я упомянул несколько лет назад ^ с React Hooks, ссылки также являются отличным способом отслеживать данные между рендерами и не ограничиваются простым захватом DOM-узлов.
Ответ 3
TL; DR Вообще говоря, refs
противоречат декларативной философии React, поэтому вы должны использовать их в качестве последнего средства. Используйте state/props
когда это возможно.
Чтобы понять, где вы используете refs
против state/props
, давайте рассмотрим некоторые принципы проектирования, которым придерживается React.
Per React документация по refs
Избегайте использования ссылок для всего, что может быть сделано декларативно.
Принципы разработки React о спасательных люках
Если какой-то шаблон, который полезен для создания приложений, сложно выразить декларативным способом, мы предоставим для него обязательный API. (и они ссылаются на ссылки здесь)
Это означает, что команда React предлагает избегать refs
и использовать state/props
для всего, что может быть сделано реактивным/декларативным способом.
@Tyler McGinnis дал очень хороший ответ, заявив также, что
Правильный (и очень полезный) способ использования ссылок - это когда вы используете их для получения некоторого значения из DOM...
Хотя вы можете сделать это, вы будете работать против философии React. Если у вас есть значение на входе, оно, безусловно, исходит из state/props
. Чтобы код оставался последовательным и предсказуемым, вы должны придерживаться там же state/props
. Я признаю тот факт, что refs
иногда дают вам более быстрое решение, поэтому, если вы делаете проверку концепции, приемлемо быстрое и грязное.
Это оставляет нам несколько конкретных вариантов использования для refs
Управление фокусом, выделением текста или воспроизведением мультимедиа. Запуск императивных анимаций. Интеграция со сторонними библиотеками DOM.
Ответ 4
Этот пост старый.
Я поделюсь своим небольшим опытом по одному делу по этому вопросу.
Я работал над большим компонентом (414 строк) с большим количеством "динамических" входов и большим количеством кэшированных данных.
(Я не работаю один над страницей, и мои чувства говорят мне, что структура кода, вероятно, могла бы быть разбита лучше, но это не главное (ну, это может быть, но я имею дело с этим)
Сначала я работал с состоянием для обработки значений входов:
const [inputsValues, setInputsValues] = useState([])
const setInputValue = (id, value) => {
const arr = [...inputsValues]
arr[id] = value
setInputsValues(arr)
}
и конечно во входах:
value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}
Рендеринг был настолько тяжелым, что изменение ввода было изменчивым, как **** (не пытайтесь удерживать клавишу нажатой, текст появится только после паузы)
Я был уверен, что смогу избежать этого, используя ссылки.
закончилось так:
const inputsRef = useRef([])
и во входах:
ref={input => (inputsRef.current[id] = input)}
[
хорошо, в моем случае Input был Material-UI TextField, так что это было:
inputRef={input => (inputsRef.current[id] = input)}
]
Благодаря этому нет повторного рендеринга, ввод плавный, функция работает точно так же. Это сэкономит циклы и расчеты, так что энергии тоже. Сделай это для земли х)
Мой вывод: useRef для входных значений может даже понадобиться.