Использовать состояние или 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 для входных значений может даже понадобиться.