javascript - Skjult input utløser ikke Reacts onChange-hendelse
Jeg står overfor et merkelig problem med inndatafeltet i React. Jeg er klar over at hidden-input ikke utløser input eller change-hendelser. Men selv om jeg utløser dem manuelt, blir ikke Reacts onChange-hendelse fortsatt kalt.
Jeg utløser begge, change og input hendelser her fordi Reacts onChange faktisk er input-hendelsen. Når jeg setter opp en hendelseslytter på inputRef (addEventListener("change",() => { ... })) for testformål, blir den kalt uten problemer. Imidlertid viser det seg at React har noen problemer med å fange den.
Her er min nåværende kode:
const [fieldValue, setFieldValue] = useState(0);
const inputRef = useRef<HTMLInputElement>(null);
const handleClick = useCallback((): void => {
if (inputRef.current) {
inputRef.current.dispatchEvent(new Event("change", { bubbles: true }));
inputRef.current.dispatchEvent(new Event("input", { bubbles: true }));
}
setFieldValue(prev => prev + 1);
}, []);
JSX :
<input type="hidden" ref={inputRef} value={fieldValue} onChange={(e) => { console.log("React:onChange"); }} />
<button type="button" onClick={handleClick}>Hit it</button>
Gjør jeg noe galt her? Hva mer må jeg gjøre for å utløse Reacts onChange-hendelse på riktig måte?
Svar #1
Hendelser i React håndteres av react-dom, gjennom forskjellige plugins. Inndatameldinger håndteres med SimpleEventPlugin (se https://github.com/facebook/react/blob/master/packages/react-dom/src/events/SimpleEventPlugin.js)
Denne pluginen mottar en hendelse og videresender den uten å forstyrre for mye. Så du kan sende den som en innebygd hendelse, og den vil bli utløst som en SyntheticEvent uten store endringer.
Endringshendelsen håndteres av ChangeEventPlugin (se https://github.com/facebook/react/blob/master/packages/react-dom/src/events/ChangeEventPlugin.js). Dette pluginet har følgende formål:
Denne pluginen oppretter en
onChange-hendelse som normaliserer endringshendelser på tvers av formelementer. Denne hendelsen utløses på et tidspunkt når det er mulig å endre elementets verdi uten å se en flimmer.
Pluginet utløser endringshendelsen, men ikke nøyaktig som den innebygde endringshendelsen. Den innebygde endringshendelsen på et tekstinndataelement, for eksempel, utløses bare ved blur. Se https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event
For noen elementer, inkludert , utløses ikke endringshendelsen før kontrollen mister fokus.
Men med React utløses det på en annen måte, ved hver endring av verdien. For å gjøre dette håndteres det av plugin-en som har disse begrensningene: Hendelsen vil kun bli utløst på disse inputtypene:
color: true,
date: true,
datetime: true,
'datetime-local': true,
email: true,
month: true,
number: true,
password: true,
range: true,
search: true,
tel: true,
text: true,
time: true,
url: true,
week: true
Så på skjulte inputfelt stopper React sendingen.
En annen begrensning er at hendelsen kun vil bli sendt hvis verdien av inndataen faktisk endres. Se
if (updateValueIfChanged(targetNode)) {
return targetInst;
}
Så selv på en støttet input, vil ikke din dispatch gå gjennom plugin-en. Du kan se det i dette utdraget, ved å manipulere en metode som brukes for å hente verdien av inputen kan du klare å sende hendelsen.
class Hello extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
//_valueTracker.getValue is used for comparing the values of the input. If you write fake value in the input it'll dispatch, anything else won't
document.getElementsByTagName('INPUT')[0]._valueTracker.getValue = () => {
return 'fake value'
}
}
render() {
const handleClick = () => {
if (this.myRef) {
this.myRef.current.dispatchEvent(new Event("change", {
bubbles: true
}));
}
};
return <div > < input type = "text"
ref = {
this.myRef
}
onChange = {
(e) => {
console.log("React:onChange");
}
}
/><button type="button" onClick={handleClick}>Hit it</button > < /div>
}
}
ReactDOM.render( <
Hello name = "World" / > ,
document.getElementById('container')
);<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container">
</div>Så for et skjult input finnes det ingen måte å få det til å fungere på (merk at dette er i samsvar med standarden). For et tekstfelt (eller andre støttede input) kan du det, men du må mer eller mindre manipulere metoden ved å sammenligne verdien før hendelsen med verdien etter hendelsen.
Svar #2
onChange-hendelsen utløses når brukeren endrer elementverdien - i ditt tilfelle endrer du programmessig inndataverdien, og dermed utløses ikke onChange
onInput-hendelser utløses når verdien endres - uansett hvordan. Derfor må du legge til onInput i stedet for onChange.
<input type="hidden" ref={inputRef} value={fieldValue} onInput={(e) => { console.log("React:onChange"); }} />
Her er et fungerende eksempel: Sandbox
