Використовувати стан або refs в компонентах React.js форми?


116

Я починаю з React.js, і я хочу зробити просту форму, але в документації я знайшов два способи зробити це.

Перший з них використовує Refs :

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: ''
  });
});

Я не бачу плюсів і мінусів двох варіантів, якщо такі існують. Дякую.


Я щось тут пропускаю? Чому ви не використовуєте об'єкт події для отримання значень форми? Це, мабуть, є єдиною причиною використання форми в першу чергу. Якщо ви не використовуєте поведінку надсилання за замовчуванням і маєте відповіді на введення, вам не потрібно їх загортати у форму.
NectarSoft

Відповіді:


143

Коротка версія: уникайте реф.


Вони погані для ремонту та втрачають багато простоти, яку надає модель WYSIWYG.

У вас форма. Потрібно додати кнопку, яка скидає форму.

  • списки:
    • маніпулювати DOM
    • render описує, як виглядала форма 3 хвилини тому
  • держава
    • setState
    • візуалізація описує, як виглядає форма

У вашому додатку є поле CCV номера та деякі інші поля у вашій програмі, які є цифрами. Тепер вам потрібно примусити користувача вводити лише цифри.

  • списки:
    • додати обробник onChange (чи не використовуємо ми рефлекси, щоб цього уникнути?)
    • маніпулюйте dom у onChange, якщо це не число
  • держава
    • у вас вже є обробник onChange
    • додайте оператор if, якщо він недійсний, нічого не робити
    • візуалізація викликається лише в тому випадку, якщо вона дасть інший результат

Е, ніколи не кажучи, прем'єр-міністр хоче, щоб ми просто зробили червону тінь, якщо вона недійсна.

  • списки:
    • зробити onChange обробник просто викликати forceUpdate або щось таке?
    • зробити рендерінг на основі ... так?
    • звідки ми отримуємо значення для перевірки у візуалізації?
    • вручну маніпулювати властивістю className dom елемента?
    • я загубився
    • переписати без реф.
    • читати з дому в візуалізації, якщо ми встановлені інакше вважаємо дійсним?
  • штат:
    • видаліть оператор if
    • зробити рендеринг перевіреним на основі цього.state

Нам потрібно повернути контроль батькові. Дані зараз є реквізитом, і нам потрібно реагувати на зміни.

  • списки:
    • реалізувати компонентDidMount, компонентWillUpdate і компонентDidUpdate
    • вручну відрізняти попередні реквізити
    • маніпулюйте домом з мінімальним набором змін
    • ей! ми реагуємо в реагуванні ...
    • є більше, але мені болять пальці
  • штат:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

Люди вважають, що рефреш є «простішим», ніж тримати його в державі. Це може бути правдою протягом перших 20 хвилин, це не вірно в моєму досвіді після цього. Поставте себе в позицію сказати "Так, я буду це робити за 5 хвилин", а не "Звичайно, я просто перепишу кілька компонентів".


3
Чи можете ви пояснити трохи більше про sed -e 's / this.state / this.props /' s / handleChange / onChange / '-i form.js?
gabrielgiussi

1
Ні, я маю на увазі фактичні зміни до дому. React.findDOMNode(this.refs.foo). Якщо ви, наприклад, зміни this.refs.foo.props.barнічого не відбудеться.
Бриганд

1
наприклад, якщо ви <input onChange={this.handleChange} value={this.state.foo} />змінили його <input onChange={this.props.handleChange} value={this.props.foo} />або змінили функцію handChange, щоб викликати зворотний дзвінок у реквізиті. Так чи інакше, це кілька невеликих очевидних змін.
Бриганд

4
Не впевнений, чи я єдиний, хто вважає вашу відповідь трохи заплутаною. Чи можете ви показати деякі зразки коду, які роблять ваші бали яснішими?
Рішабх

2
Мати 50+ входів на екрані, а відображення кожного за будь-якої зміни стану небажано. Компонентизація кожного inputполя, де кожне підтримує свій власний стан, є ідеальним. У якийсь момент нам потрібно узгодити ці різні незалежні держави з якоюсь більшою моделлю. Можливо, у нас є автоматичне збереження на таймері, або ми просто економимо на componentWillUnmountцьому. Тут я вважаю refsідеальним, під час узгодження ми вибираємо stateзначення з кожного ref, і жодне не мудріше. Я згоден у більшості випадків, stateце відповідь, але з великою кількістю inputs, використовуючи правильну refsсхему, є користю для продуктивності
люкс

105

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

Настрій "не використовувати реф." Правильний, коли говорити про їх використання для компонентних екземплярів. Це означає, що ви не повинні використовувати refs як спосіб захоплення компонентних екземплярів і виклику методів на них. Це неправильний спосіб використання посилань, і це те, коли рефлекси швидко йдуть на південь.

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

2019 редагувати: Привіт друзі майбутнього. На додаток до того, що я згадував кілька років тому ^, за допомогою React Hooks, refs також є прекрасним способом відстеження даних між рендерами і не обмежується лише захопленням DOM-вузлів.


3
Ваш останній абзац має ідеальний сенс, але чи можете ви уточнити свій другий абзац? Який конкретний приклад захоплення екземпляра компонента та виклику методу, який вважався б невірним?
Денні Лібін

2
Я погодився би з цим. Я використовую рефлекси, якщо / поки мені не потрібно перевірити чи маніпулювати значенням поля. Якщо мені потрібно перевірити зміни або змінити значення програмно, то я використовую стан.
Крістофер Девіс

1
Я згоден і з цим. Під час фази відкриття я навмисно підійшов до екрана з великою кількістю входів з наївністю. Усі вхідні значення, що зберігаються на карті (у стані), введені id. Потрібно сказати, що продуктивність постраждала після встановлення стану та надання 50+ входів (деяких матеріалів, що були важкими!) На таких незначних змінах інтерфейсу, як натискання прапорця, не було ідеальним. Компонентизація кожного входу, який може підтримувати власний стан, здавалася правильним підходом. Якщо потрібне примирення, просто зазирніть у refsта отримайте значення держави. Здається, насправді приємний візерунок насправді.
люкс

2
Я повністю згоден. На мою думку, прийнята відповідь занадто розпливчаста.
Джеймс Райт

Я згоден. Розробляючи загальний компонент форми, це виявляє больові точки керованих компонентів та керування фокусом, керування помилками тощо. Фактично не можна мати чистої архітектури. Поговоріть зі мною, якщо потрібно. Я переміщую свої компоненти на посилання.
kushalvm

6

TL; DR Загалом кажучи, refsсуперечте декларативній філософії React , тому вам слід використовувати їх як крайній захід. Використовуйте, state / propsколи це можливо.


Щоб зрозуміти, де ви використовуєте refsvs state / props, давайте розглянемо деякі принципи дизайну, які реагує React.

Документація про реагування оrefs

Уникайте використання посилань на будь-що, що можна зробити декларативно.

Принципи дизайну Per React щодо врізаних люків

Якщо якийсь шаблон, який корисний для створення додатків, важко виразити декларативним способом, ми надамо імперативний API для нього. (і вони посилаються на посилання тут)

Що означає, що команда React пропонує уникати refsта використовувати state / propsбудь-що, що можна зробити реактивно / декларативно.

@Tyler McGinnis дав дуже хорошу відповідь , заявивши також, що це

Правильний (і дуже корисний) спосіб використання посилань - це коли ви використовуєте їх, щоб отримати деяку цінність від DOM ...

Поки ти можеш це зробити, ти будеш працювати проти філософії React. Якщо ви маєте значення у вхідних даних, це, безумовно, походить від state / props. Щоб код був послідовним і передбачуваним, слід дотримуватисяstate / props цього. Я визнаю той факт, що refsіноді дає вам швидше рішення, тому, якщо ви докажете свою концепцію, швидке та брудне є прийнятним.

Це дає нам кілька конкретних випадків використання дляrefs

Керування фокусом, вибором тексту або відтворенням медіа. Запуск імперативних анімацій. Інтеграція з сторонніми бібліотеками DOM


5

Ця публікація стара.

Я поділюсь своїм невеликим досвідом щодо одного випадку з цього питання.

Я працював над великим компонентом (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 було TextField Material-UI TextField, так що:

inputRef={input => (inputsRef.current[id] = input)}

]

Завдяки цьому відтворення не відбувається, введення плавне, функціональність працює так само. Це заощадить цикли та обчислення, тому й енергію. Зробіть це для землі x)

Мій висновок: використання UseRef для значення входів може бути навіть необхідним.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.