Использовать состояние или ссылки в компонентах формы 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: ''
  });
});

Я не вижу плюсов и минусов двух альтернатив, если таковые существуют. Благодарю.

3 ответа

Решение

Краткая версия: избегайте ссылок.


Они плохо подходят для сопровождения и теряют большую часть простоты визуализации модели WYSIWYG.

У вас есть форма. Вам нужно добавить кнопку, которая сбрасывает форму.

  • рефов:
    • манипулировать DOM
    • render описывает, как форма выглядела 3 минуты назад
  • государство
    • SetState
    • render описывает, как выглядит форма

У вас есть поле ввода номера CCV и некоторые другие поля в вашем приложении, которые являются числами. Теперь нужно принудительно вводить только пользовательские цифры.

  • рефов:
    • добавить обработчик onChange (разве мы не используем ссылки, чтобы избежать этого?)
    • манипулировать домом в onChange, если это не число
  • государство
    • у вас уже есть обработчик onChange
    • добавить оператор if, если он недействителен, ничего не делать
    • рендер вызывается только в том случае, если он даст другой результат

Эх, неважно, премьер-министр хочет, чтобы мы просто сделали красную рамку-тень, если она недействительна.

  • рефов:
    • сделать обработчик onChange просто вызвать forceUpdate или что-то?
    • сделать вывод рендеринга на основе... а?
    • где мы получаем значение для проверки в рендере?
    • вручную манипулировать свойством className dom элемента?
    • я потерялся
    • переписать без ссылок?
    • читать из домена в рендере, если мы смонтированы, в противном случае допустим?
  • государство:
    • удалить оператор if
    • сделать визуализацию валидной на основе this.state

Нам нужно вернуть контроль родителю. Данные теперь в реквизите, и мы должны реагировать на изменения.

  • рефов:
    • реализовать componentDidMount, componentWillUpdate и componentDidUpdate
    • вручную разнести предыдущие реквизиты
    • манипулировать домом с минимальным набором изменений
    • Привет! мы реализуем реагировать в реагировать...
    • это больше, но мои пальцы болят
  • государство:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

Люди думают, что рефери "проще", чем держать их в состоянии. Это может быть правдой в течение первых 20 минут, это не так в моем опыте после этого. Поставьте себя в положение, чтобы сказать: "Да, я сделаю это через 5 минут", а не "Конечно, я просто перепишу несколько компонентов".

Я видел, как несколько человек цитировали приведенный выше ответ в качестве причины "никогда не использовать ссылки", и я хочу высказать свое (а также несколько других разработчиков React, с которыми я говорил).

Мнение "не использовать ссылки" является правильным, когда речь идет об использовании их для экземпляров компонентов. Это означает, что вы не должны использовать ссылки как способ захвата экземпляров компонентов и вызова методов для них. Это неправильный способ использовать ссылки, и они очень быстро уходят на юг.

Правильный (и очень полезный) способ использования ссылок - это когда вы используете их для получения некоторого значения из DOM. Например, если у вас есть поле ввода, присоединяющее ссылку к этому входу, тогда захват значения позже через ссылку просто подойдет. Без этого вам придется пройти довольно организованный процесс для обновления поля ввода в соответствии с вашим локальным состоянием или хранилищем потоков - что кажется ненужным.

Это старый пост

Я поделюсь своим небольшим опытом по одному делу по этому поводу.

Я работал над большим компонентом (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)}

]

Благодаря этому нет повторного рендеринга, ввод плавный, функциональность работает точно так же. Это сэкономит циклы и вычисления, а значит, и энергию. Сделайте это для земли x)

Мой вывод: может даже понадобиться useRef для значений input.

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.

Другие вопросы по тегам