javascript - I React, vad är skillnaden mellan onChange och onInput?
Jag har försökt söka efter ett svar på detta, men de flesta av dem är utanför React-kontexten, där onChange triggas vid blur.
När jag utför olika tester verkar jag inte kunna avgöra hur dessa två händelser skiljer sig åt (när de används på ett textområde). Kan någon förklara detta?
Svar #1
Det verkar som att det inte finns någon verklig skillnad
React fäster av någon anledning lyssnare för Component.onChange till DOM-element.oninput-händelsen. Se noten i dokumentationen om formulär:
React-dokumentation - Formulär
Det finns fler människor som blir överraskade av detta beteende. För mer information, se detta problem på Reacts felspårningslista:
Dokumentera hur Reacts onChange relaterar till onInput #3964
Citat från kommentarerna om det problemet:
Jag förstår inte varför React valde att låta onChange bete sig som onInput gör. Så vitt jag kan se har vi inget sätt att få tillbaka det gamla onChange-beteendet. Dokumentationen hävdar att det är ett "felaktigt namn", men det är det egentligen inte, det utlöses när det sker en förändring, bara inte förrän inputen också tappar fokus.
För validering vill vi ibland inte visa valideringsfel förrän användaren har slutat skriva. Eller kanske vill vi helt enkelt inte göra en ny renderingen vid varje tangenttryckning. Nu är det enda sättet att göra det med onBlur, men nu måste vi också kontrollera manuellt att värdet har ändrats.
Det är ingen stor grej, men det verkar för mig som att React slängde bort en användbar händelse och avvek från standardbeteendet när det redan fanns en händelse som gör detta.
Jag håller med kommentaren till 100%... Men jag antar att att ändra det nu skulle skapa fler problem än det löser eftersom så mycket kod redan har skrivits som är beroende av detta beteende.
React är inte en del av den officiella Web API-samlingen
Även om React är byggt ovanpå JS och har sett en enorm adoptionsgrad, finns teknologin React till för att dölja en hel del funktionalitet under sitt eget (ganska lilla) API. Ett område där detta är uppenbart är i eventsystemet, där det händer mycket under ytan som faktiskt är radikalt annorlunda än det standard DOM-eventssystemet. Inte bara när det gäller vilka events som gör vad, utan också när data får fortsätta existera vid vilken fas av eventhanteringen. Du kan läsa mer om det här:
React-händelsesystem
Svar #2
Det finns ingen skillnad
React har inte beteendet hos standard 'onChange'-händelsen. 'onChange' som vi ser i React har beteendet hos standard 'onInput'-händelsen. Så för att svara på din fråga finns det ingen skillnad mellan dem i React. Jag har tagit upp ett problem på GitHub angående detta och detta är vad de har att säga om det:
Jag tror att vid den tidpunkt då detta beslut togs (~4 år sedan?), fungerade onInput inte konsekvent mellan webbläsare, och det var förvirrande för personer som kom till webben från andra plattformar, eftersom de skulle förvänta sig att “change ”-händelsen skulle utlösas vid varje ändring. I fallet med React är det ett större problem eftersom om man inte hanterar change tillräckligt snabbt, uppdateras de kontrollerade inputfälten aldrig, vilket får människor att tro att React är trasigt. Så teamet valde att kalla det onChange.
I efterhand kanske det hade varit en bättre idé att polyfilla onInput och behålla dess namn istället för att ändra beteendet hos en annan händelse. Men det tåget har gått för länge sedan. Vi kanske återvänder till detta beslut i framtiden, men jag skulle bara uppmuntra dig att se det som en egenhet hos React DOM (vilket du kommer vänja dig vid ganska snabbt).
https://github.com/facebook/react/issues/9567
Denna artikel kommer också att ge mer insikt. Som en lösning på att standard 'onChange' saknas, föreslår artikeln att man lyssnar på 'onBlur'-händelsen.
https://www.peterbe.com/plog/onchange-in-reactjs
Svar #3
En skillnad verkar vara att onChange inte utlöses när man väljer och ersätter ett tecken med samma tecken, medan onInput gör det.
Se denna sandbox: https://codesandbox.io/s/react-onchange-vs-oninput-coggf?file=/src/App.js
- Skriv "A" i fältet, sedan välj allt och skriv "B". Detta kommer att utlösa 4 händelser, 2
onChangeoch 2onInput. - Välj nu allt och skriv "B" igen, detta kommer att utlösa en ny
onInput-händelse, men ingenonChange.
Svar #4
För alla som råkade stöta på detta problem och letade efter ett sätt att lyssna efter det faktiska DOM-baserade change-händelsen, så här gjorde jag det (skrivet i 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} />;
}
}
Vänligen låt mig veta om du ser sätt att förbättra detta tillvägagångssätt eller stöter på problem med det. Till skillnad från blur triggas change-händelsen även när användaren trycker på enter och triggas endast om värdet faktiskt har ändrats.
Jag håller fortfarande på att skaffa erfarenhet med denna CustomInput-komponent. Till exempel beter sig kryssrutorna märkligt. Jag måste antingen invertera event.target.checked i onChange-hanteraren samtidigt som jag skickar värdet till kryssrutan med checked, eller ta bort denna inversion när jag skickar värdet till kryssrutan med defaultChecked, men detta gör att flera kryssrutor som representerar samma tillstånd på olika ställen på sidan inte håller sig synkroniserade. (I båda fallen skickade jag inte med en onInput-hanterare till CustomInput för kryssrutorna.)
Svar #5
Som du kan se i olika kommentarer här, behandlar React onChange och onInput på samma sätt och så, istället för att diskutera för- och nackdelarna med detta beslut. Här är lösningen.
Använd onBlur när du inte vill bearbeta användarens redigeringar förrän de är klara. :)
