Pesquisa de site

javascript - No React, qual é a diferença entre onChange e onInput?


Eu tentei procurar uma resposta para isso, mas a maioria está fora do contexto do React, onde onChange é acionado ao perder o foco.

Ao realizar vários testes, não consigo perceber como esses dois eventos são diferentes (quando aplicados a uma área de texto). Alguém pode esclarecer isso?

Resposta #1

Parece que não há diferença real

O React, por algum motivo, anexa listeners para Component.onChange ao evento element.oninput do DOM. Veja a nota na documentação sobre formulários:

Documentação do React - Formulários

Há mais pessoas que estão surpresas com esse comportamento. Para mais detalhes, consulte este problema no rastreador de problemas do React:

Documente como o onChange do React se relaciona com o onInput #3964

Citação dos comentários sobre essa questão:

Eu não entendo por que o React escolheu fazer o onChange se comportar como o onInput. Pelo que posso perceber, não temos como recuperar o comportamento antigo do onChange. A documentação afirma que é um "nome inadequado", mas na verdade não é, ele dispara quando há uma mudança, apenas não até que o input também perca o foco.

Para validação, às vezes não queremos mostrar erros de validação até que eles terminem de digitar. Ou talvez nós apenas não queiramos uma re-renderização a cada pressionamento de tecla. Agora, a única maneira de fazer isso é com onBlur, mas agora também precisamos verificar manualmente se o valor mudou.

Não é um grande problema, mas me parece que o React descartou um evento útil e se desviou do comportamento padrão quando já havia um evento que faz isso.

Concordo 100% com o comentário... Mas acho que mudar isso agora traria mais problemas do que resolveria, já que tanto código já foi escrito que depende desse comportamento.

React não faz parte da coleção oficial de APIs da Web

Embora o React seja construído sobre o JS e tenha tido uma taxa de adoção enorme, como tecnologia o React existe para ocultar muitas funcionalidades sob sua própria API (relativamente pequena). Uma área onde isso é óbvio é no sistema de eventos, onde há muito acontecendo sob a superfície que é realmente radicalmente diferente do sistema de eventos padrão do DOM. Não apenas em termos de quais eventos fazem o quê, mas também em termos de quando os dados podem persistir em cada estágio do processamento de eventos. Você pode ler mais sobre isso aqui:

Sistema de Eventos do React

Resposta #2

Não há diferença

O React não possui o comportamento padrão do evento 'onChange'. O 'onChange' que vemos no React tem o comportamento do evento padrão 'onInput'. Então, para responder à sua pergunta, não há diferença entre eles no React. Eu abri uma questão no GitHub sobre isso e isto é o que eles têm a dizer sobre o assunto:

Eu acho que na época em que essa decisão foi tomada (~4 anos atrás?), o onInput não funcionava de forma consistente entre os navegadores, e era confuso para pessoas que vinham da web de outras plataformas, pois esperariam que o evento “change” fosse disparado a cada alteração. No caso do React, isso é um problema maior porque, se você não conseguir lidar com o change rápido o suficiente, os inputs controlados nunca são atualizados, fazendo as pessoas pensarem que o React está quebrado. Então a equipe optou por chamá-lo de onChange.

Em retrospectiva, talvez tivesse sido uma ideia melhor criar um polyfill para onInput e manter seu nome, em vez de mudar o comportamento de outro evento. Mas esse navio partiu há muito tempo. Podemos reconsiderar essa decisão no futuro, mas eu apenas encorajaria você a tratá-la como uma peculiaridade do React DOM (à qual você se acostumará bem rápido).

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

Além disso, este artigo fornecerá mais informações. Como solução alternativa para o 'onChange' padrão estar ausente, o artigo sugere ouvir o evento 'onBlur'.

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

Resposta #3

Uma diferença parece ser que onChange não é disparado ao selecionar e substituir um caractere pelo mesmo caractere, enquanto onInput é.

Veja este sandbox: https://codesandbox.io/s/react-onchange-vs-oninput-coggf?file=/src/App.js

  • Digite "A" no campo, depois selecione tudo e digite "B". Isso acionará 4 eventos, 2 onChange e 2 onInput.
  • Agora selecione tudo e digite "B" novamente, isso irá acionar um novo evento onInput, mas nenhum onChange.

Resposta #4

Para qualquer pessoa que tenha esbarrado neste problema procurando uma forma de escutar o evento change real, baseado no DOM, é assim que eu fiz (escrito em 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} />;
    }
}

Por favor, me avise se você vir maneiras de melhorar essa abordagem ou encontrar problemas com ela. Diferente do blur, o evento change também é acionado quando o usuário pressiona enter e só é acionado se o valor realmente mudou.

Ainda estou ganhando experiência com este componente CustomInput. Por exemplo, checkboxes se comportam de maneira estranha. Eu ou tenho que inverter event.target.checked no manipulador onChange enquanto passo o valor para o checkbox com checked, ou eliminar essa inversão ao passar o valor para o checkbox com defaultChecked, mas isso então quebra o fato de que vários checkboxes representando o mesmo estado em diferentes lugares da página mantêm-se sincronizados. (Em ambos os casos, eu não passei um manipulador onInput para o CustomInput para checkboxes.)

Resposta #5

Como você pode ver em vários comentários aqui, o React trata onChange e onInput da mesma forma e, portanto, em vez de debater os méritos dessa decisão, aqui está a solução.

Use onBlur quando você não quiser processar as edições do usuário até que ele tenha terminado. :)

Artigos relacionados