В React какая разница между onChange и onInput?

86

Я попытался найти ответ на этот вопрос, но большинство из них находятся вне контекста React, где onChangeсрабатывает размытие.

Выполняя различные тесты, я не могу сказать, чем отличаются эти два события (применительно к текстовой области). Может кто-нибудь пролить некоторый свет на это?

ffxsam
источник
1
Я отредактировал свой пост, чтобы было понятнее. Я говорил конкретно о текстовом поле, а не о переключателях или флажках.
ffxsam 07
Это совершенно неверно, React - это не просто JS. И в некоторых случаях события ведут себя немного иначе (например, onChange). И нет, вставка текста в текстовое поле (в React) запускает оба onChangeи onInput. Не стесняйтесь тестировать на скрипке, и вы увидите.
ffxsam 07
Для <input> и <textarea> onChange заменяет - и, как правило, его следует использовать вместо - встроенный обработчик событий oninput в DOM.
Roko C. Buljan
Я полагаю, что onChange - более безопасная ставка. Я даже попытался программно изменить значение textarea, думая, что, возможно, onChangeсработает и onInputнет, но оба срабатывают.
ffxsam 07
Да, теперь, просмотрев немного React Docs, я вижу, что React делает кое-что вроде jQuery, нормализует события и да. onChange кажется предпочтительным способом. Ага. React - это не что иное, как JS. Особой магии нет. Просто правила.
Roko C. Buljan

Ответы:

79

Кажется, нет реальной разницы

React по какой-то причине присоединяет слушателей Component.onChangeк element.oninputсобытию DOM . См. Примечание в документации к формам:

React docs - Формы

Такого поведения удивляет больше людей. Дополнительные сведения см. В этой проблеме в системе отслеживания проблем React:

Документируйте, как onChange в React соотносится с onInput # 3964

Цитата из комментариев по этому поводу:

Я не понимаю, почему React решил заставить onChange вести себя так же, как onInput. Насколько я могу судить, у нас нет возможности вернуть прежнее поведение onChange. Документы утверждают, что это «неправильное название», но на самом деле это не так, он срабатывает, когда есть изменение, но только до тех пор, пока ввод также не теряет фокус.

Для проверки иногда мы не хотим отображать ошибки проверки, пока они не закончат ввод. Или, может быть, мы просто не хотим повторного рендеринга при каждом нажатии клавиши. Теперь единственный способ сделать это - использовать onBlur, но теперь нам также нужно проверить, изменилось ли значение вручную.

Это не такая уж большая проблема, но мне кажется, что React выбросил полезное событие и отклонился от стандартного поведения, когда уже было событие, которое это делает.

Я согласен на 100% с комментарием ... Но я полагаю, что его изменение сейчас принесет больше проблем, чем решит, поскольку уже было написано так много кода, который полагается на это поведение.

React не является частью официальной коллекции веб-API

Несмотря на то, что React построен на основе JS и получил огромное распространение, существует технология React, позволяющая скрыть множество функций под собственным (довольно маленьким) API. Однажды область, где это очевидно, находится в системе событий, где много чего происходит под поверхностью, что на самом деле радикально отличается от стандартной системы событий DOM. Не только с точки зрения того, какие события что делают, но и с точки зрения того, когда данные могут сохраняться на каком этапе обработки события. Вы можете прочитать об этом здесь:

Система событий React

Стейн де Витт
источник
Последний абзац вводит в заблуждение / не соответствует действительности.
Rounce
1
React - это не фреймворк (где он обеспечивает маршрутизацию, постоянство, управление сетевым вводом-выводом и т. Д.?), Это библиотека, которая предоставляет базовую абстракцию для управления деревьями отображения через специфичные для платформы бэкенды (react-dom, react-native, так далее.).
Rounce
7
Вау, ладно. Я вроде как согласен, что это больше библиотека, чем фреймворк, но назвать абзац вводящим в заблуждение / неверным из-за этого ?? Я также не согласен с тем, что фреймворк должен обеспечивать все аспекты веб-приложения ... Существуют, например, фреймворки маршрутизации или такие вещи, как redux, который представляет собой фреймворк управления состоянием. На мой взгляд, фреймворк позволяет вам заполнять части функционирующей машины. В случае Redux вы заполняете редукторы. В случае Express вы заполняете обработчики запросов и промежуточное ПО. И т.д. Но различие - это, мягко говоря, серая зона.
Stijn de Witt
4
полностью согласен. спорить о различии между библиотекой и фреймворком - пустая трата времени. просто зависит от того, на каком уровне абстракции вы работаете.
swyx 01
1
@chadsteele Спасибо, дружище, приятно слышать, что это помогло тебе
Стейн де Витт
21

Нет никакой разницы

React не имеет поведения события onChange по умолчанию. 'OnChange', который мы видим в реакции, имеет поведение события onInput по умолчанию. Итак, чтобы ответить на ваш вопрос, у них обоих нет разницы в реакции. Я поднял вопрос о том же на GitHub, и вот что они говорят по этому поводу:

Я думаю, что в то время, когда было принято это решение (~ 4 года назад?), OnInput не работал согласованно между браузерами и сбивал с толку людей, заходящих в Интернет с других платформ, поскольку они ожидали, что событие «изменения» произойдёт. огонь при каждом изменении. В случае React это более серьезная проблема, потому что, если вы не сможете обработать изменения достаточно быстро, контролируемые входные данные никогда не обновятся, что заставляет людей думать, что React сломан. Команда назвала его onChange.

Оглядываясь назад, возможно, было бы лучше использовать polyfill onInput и сохранить его имя, чем изменять поведение другого события. Но этот корабль уже давно отплыл. Мы могли бы пересмотреть это решение в будущем, но я просто рекомендую вам рассматривать его как причуду React DOM (к которой вы довольно быстро привыкнете).

https://github.com/facebook/react/issues/9567

Также эта статья предоставит больше информации. В качестве временного решения проблемы отсутствия onChange по умолчанию в статье предлагается прослушать событие onBlur.

https://www.peterbe.com/plog/onchange-in-reactjs

Нихил Гоял
источник
3

Недавно у меня возникла ошибка, из-за которой onChangeне разрешалось копирование и вставка в поле ввода IE11. В то время как onInputсобытие допускало такое поведение. Я не смог найти никакой документации, которая описывала бы это в документах, но это показывает, что есть разница между ними (ожидаемая или нет).

Алан Соуза
источник
2

Как вы можете видеть в различных комментариях здесь, React рассматривает onChange и onInput одинаково, и поэтому, а не обсуждает достоинства этого решения. Вот решение.

Используйте onBlur, если вы не хотите обрабатывать правки пользователя, пока они не будут сделаны. :)

Чад Стил
источник
1

Для всех, кто наткнулся на эту проблему, ища способ прослушать реальное changeсобытие, основанное на DOM , я сделал это следующим образом (написано на TypeScript):

import { Component, createElement, InputHTMLAttributes } from 'react';

export interface CustomInputProps {
    onChange?: (event: Event) => void;
    onInput?: (event: Event) => void;
}

/**
 * This component restores the 'onChange' and 'onInput' behavior of JavaScript.
 *
 * See:
 * - https://reactjs.org/docs/dom-elements.html#onchange
 * - https://github.com/facebook/react/issues/3964
 * - https://github.com/facebook/react/issues/9657
 * - https://github.com/facebook/react/issues/14857
 */
export class CustomInput extends Component<Omit<InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'onInput' | 'ref'> & CustomInputProps> {
    private readonly registerCallbacks  = (element: HTMLInputElement | null) => {
        if (element) {
            element.onchange = this.props.onChange ? this.props.onChange : null;
            element.oninput = this.props.onInput ? this.props.onInput : null;
        }
    };

    public render() {
        return <input ref={this.registerCallbacks} {...this.props} onChange={undefined} onInput={undefined} />;
    }
}

Пожалуйста, дайте мне знать, если вы видите способы улучшить этот подход или у вас возникнут проблемы с ним. В отличие от blurэтого changeсобытие также запускается, когда пользователь нажимает клавишу ввода, и запускается только в том случае, если значение действительно изменилось.

Я все еще набираюсь опыта с этим CustomInputкомпонентом. Например, странно ведут себя флажки. Мне нужно либо инвертировать event.target.checkedв onChangeобработчике, передавая значение флажку, checkedлибо избавиться от этой инверсии при передаче значения флажку, defaultCheckedно это затем нарушает синхронизацию нескольких флажков, представляющих одно и то же состояние в разных местах на странице . (В обоих случаях я не передавал onInputобработчик флажкам CustomInputfor.)

Каспар Эттер
источник