Möchten Sie eine Funktion anfordern oder einen Fehler melden?
Fehler!
Wie ist das aktuelle Verhalten?
Beim Rendern eines input
-Elements vom Typ checkbox
mit einem onClick
und onChange
Handler wird onChange
immer noch aufgerufen, obwohl event.preventDefault()
wird im onClick
Handler aufgerufen.
Wenn das aktuelle Verhalten ein Fehler ist, geben Sie die Schritte zum Reproduzieren und wenn möglich eine minimale Demo des Problems über https://jsfiddle.net oder ähnliches an (Vorlage: https://jsfiddle.net/reactjs/69z2wepo/).
Was ist das erwartete Verhalten?
Das Aufrufen von event.preventDefault
im Handler onClick
sollte verhindern, dass die Standardaktion ausgeführt wird (oder deren Wirkung rückgängig macht), dh den Wert des Elements input
aktualisieren. Dies sollte verhindern, dass ein change
Ereignis-Listener aufgerufen wird. Informationen zum erwarteten Verhalten finden Sie unter
Welche Versionen von React und welcher Browser / welches Betriebssystem sind von diesem Problem betroffen?
Getestet mit einem Build von Master, macOS 10.12.2, verifiziert in:
Safari 10.0.2 ruft in beiden Fällen den Ereignis-Listener change
.
Das change
-Ereignis wird vom ChangeEventPlugin
als Antwort auf topChange
, bevor Ihr onClick
-Handler überhaupt aufgerufen wird (also vor dem preventDefault
call), hier: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/eventPlugins/ChangeEventPlugin.js#L338
Dieses Plugin versucht herauszufinden, ob sich der Wert des Kontrollkästchens ändert, und wenn ja, wird das Ereignis change
in die Warteschlange gestellt. Es verwendet die inputValueTracking
-Funktionalität, um den vorherigen Wert mit dem nächsten Wert zu vergleichen, um diese Entscheidung zu treffen: https://github.com/facebook/react/blob/master/src/renderers/dom/shared/ inputValueTracking.js # L154
Die nextValue
folgt direkt aus dem DOM entnommen: value = isCheckable(node) ? '' + node.checked : node.value;
https://github.com/facebook/react/blob/master/src/renderers/dom/shared/inputValueTracking.js# L56
Das Problem ist, dass der node.checked
zu diesem Zeitpunkt vorübergehend wahr ist. Nach dem ersten Klick lautet er also wie folgt:
lastValue == false
(richtig)
nextValue == true
(falsch)
und beim nächsten Klicken auf das Kontrollkästchen wird das Ereignis change
nicht mehr ausgelöst, da die folgenden Werte vorliegen:
lastValue == true
(falsch)
nextValue == true
(falsch)
Insgesamt scheint das Problem zu sein, dass React das DOM nach dem Wert von checked
des Knotens fragt, bevor der PreventDefault in onClick
aufgerufen werden kann.
Vielen Dank an @karelskopek und @Mintaffee für Ihre Hilfe beim Eingraben.
@aweary Denkst du, das ist es wert, gelöst zu werden?
Kein Fortschritt mit diesem? Ich verwende React v16.2 und das Verhalten ist das gleiche - onChange wird beim ersten Mal ausgelöst und nachfolgende Klicks lösen es nicht aus. Ich würde hier ein Thema mit ziemlich hoher Priorität sagen.
Ist das verwandt? preventDefault
das in einem Kontrollkästchen aufgerufen wird onChange
dass React und der Browserstatus nicht mehr synchron sind: https://codesandbox.io/s/0qpr936xkv
Immer noch ein Problem in React 16.8.6. Eine mögliche Problemumgehung besteht darin, alles in onClick
handler zu erledigen:
const radios = ['one', 'two', 'three'];
class Row extends Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
this.onChange = this.onChange.bind(this);
}
render() {
const { value } = this.props;
return (
<div className="row">
<div className="radio-group">
{radios.map(radio => (
<label key={radio} className="radio">
<input
type="radio"
name="radio"
value={radio}
checked={radio === value}
onClick={this.onClick}
onChange={this.onChange}
/><span>Radio</span>
</label>
))}
</div>
</div>
);
}
onClick(event) {
// Check something to prevent radio change
if (...) {
event.preventDefault();
return;
}
// Sync value in the store
this.props.setValue(event.target.value);
}
onChange() {
// We need this empty handler to suppress React warning:
// "You provided a `checked` prop to a form field without an `onChange` handler.
// This will render a read-only field. If the field should be mutable use `defaultChecked`.
// Otherwise, set either `onChange` or `readOnly`"
}
}
Wenn Sie eine kontrollierte Komponente verwenden
onChange(event) {
// Check something to prevent radio change
if (...) {
return;
}
// Sync value in the store
this.props.setDateTime(event.target.value);
}
Für eine einfachere Lösung können Sie das Ereignis e.preventDefault on onMouseDown ausführen, um zu verhindern, dass onChange ausgelöst wird.
onMouseDown(e) {
if (...) {
e.preventDefault();
return;
}
}
Hilfreichster Kommentar
Ist das verwandt?
preventDefault
das in einem Kontrollkästchen aufgerufen wirdonChange
dass React und der Browserstatus nicht mehr synchron sind: https://codesandbox.io/s/0qpr936xkv