Warnung: Dieses synthetische Ereignis wird aus Performance-Gründen wiederverwendet

Lesezeit: 8 Minuten

Benutzer-Avatar
Raymi

Ich habe an einem einfachen React-Redux-Todo-Beispiel für eine Klasse gearbeitet und bin auf mehrere Warnmeldungen gestoßen, die jedes Mal in der Konsole angezeigt werden, wenn ich eine Checkbox-Eingabe aktiviere und deaktiviere.

Sie können die Warnungen in den folgenden Bildern sehen.

Warnung Fehlerbild

Ich habe auch eine Google-Suche nach der Warnmeldung durchgeführt, konnte aber keine funktionierende Lösung finden. Außerdem fiel mir auf, dass es so aussieht, als würde es versuchen, auf jede Eigenschaft des nativen Ereignisses und des DOM-Elements zuzugreifen.

Dies ist der Code für die Präsentationskomponente, die das Eingabe-Kontrollkästchen enthält

class TodoItem extends React.Component {
  state = {
    isChecked: false
  };
  handleCheckbox = () => {
    this.setState({
      isChecked: !this.state.isChecked
    });
  };
  render() {
    const { todos, onItemClick } = this.props;
    const { isChecked } = this.state;
    return (
      <div>
        <ul>
          {todos.map((todo, id) => {
            return (
              <li key={id} onClick={onItemClick}>
                <input
                  onChange={this.handleCheckbox}
                  type="checkbox"
                  checked={isChecked}
                />
                <label>
                  <span />
                  {todo.textInput}
                </label>
              </li>
            );
          })}
        </ul>
      </div>
    );
  }
}

export default TodoItem;

Ich habe das Beispiel auch auf CodeSandbox hochgeladen: https://codesandbox.io/s/k0mlxk1yqv

Wenn Sie diesen Fehler wiederholen möchten, müssen Sie der Aufgabenliste ein Element hinzufügen und auf das Kontrollkästchen klicken, um es ein paar Mal zu aktivieren und zu deaktivieren.

Wenn jemand eine Ahnung hat, warum diese Warnzeichen immer wieder erscheinen und wie man sie deaktiviert, würde ich mich sehr über Ihren Beitrag freuen 🙂

  • Ich habe gerade Ihren Code in der Sandbox ausprobiert und kann die Fehlermeldung, die Sie erhalten, nicht replizieren. Wird es durch etwas anderes als die Aktivierungs-/Deaktivierungsaktion ausgelöst?

    – Chetan Jadhav-CD

    26. März 2018 um 20:50 Uhr

  • Außerdem hat die Sandbox nicht wirklich den Code, den Sie hier eingefügt haben …

    – Chetan Jadhav-CD

    26. März 2018 um 20:52 Uhr

  • @ChetanJadhavCD: Vielen Dank für deine Antwort. Der Code in der Sandbox wurde aktualisiert. Wenn Sie aktualisieren, können Sie es sehen. In Bezug auf Ihre andere Frage werden die Warnmeldungen ausgelöst, wenn ich die Aktion zum Aktivieren / Deaktivieren mehr als zweimal ausführe. Sie können den Fluss im folgenden gif sehen imgur.com/a/pZOON

    – Raimi

    26. März 2018 um 21:12 Uhr

  • Schaue auf die input.onChange und li.onClick. Beim Anklicken input das click Ereignis verursacht onChange und propagiert dann an seine Eltern – li. Dann li.onClick Der Rückruf wird ausgelöst und React versucht, das synthetische Ereignis wiederzuverwenden.

    – Ivan Burnaev

    26. März 2018 um 21:25 Uhr


  • onClick={onItemClick} Sie übergeben ein Ereignis als Argument an die onItemClick aber in deinem Containercode habe ich gesehen, dass du darauf wartest id – Überprüfen Sie es pls.

    – Ivan Burnaev

    26. März 2018 um 21:33 Uhr

Benutzer-Avatar
w35l3y

Dies geschah, weil die event implizit weitergegeben onItemClick wird in einem asynchronen Kontext verwendet.
Wie Andre Lemay sagte, sollten Sie Ihre Anforderungen lokalen Variablen zuweisen und auf sie verweisen.

In meinem Fall hatte ich diesen Code:

handleInput = e => { // <-- e = synthetic event
  this.setState(state => ({ // <-- asynchronous call
    data: {
      ...state.data,
      [e.target.name]: e.target.value // <-- this was causing the warnings (e.target is in an asynchronous context)
    }
  }));
};

Dann habe ich es geändert zu:

handleInput = e => {
  const { name, value } = e.target; // <-- moved outside asynchronous context

  this.setState(state => ({
    data: {
      ...state.data,
      [name]: value
    }
  }));
};

  • Ich bin sicher, das ist dokumentiert setState ist asynchron, aber in diesem Zusammenhang darauf hinzuweisen, war für mich sehr hilfreich.

    – Jakob Bäcker

    20. Mai 2020 um 12:10 Uhr

  • Mein Held, mein Retter 八(^□^*)

    – Harvey Connor

    28. Mai 2020 um 5:17 Uhr

Benutzer-Avatar
Adam Orłowski

Ich würde vorschlagen, zwei Lösungen auszuprobieren:

Erste Änderung

onChange={this.handleCheckbox}

zu

onChange={() => this.handleCheckbox()}

Wenn das nicht funktioniert, in ‘handleCheckbox’ hinzufügen event.persist(); So was:

handleCheckbox = (event) => {
  event.persist();
  this.setState({
    isChecked: !this.state.isChecked
  });
};

  • Die erste Lösung, die Sie vorgeschlagen haben, funktioniert für mich, aber ich frage mich, warum? Wie ist geben () => this.handleCheckbox() anders als nur vorbei this.handleCheckbox außer dem ersten, der eine Schließung um eine Funktion ist?

    – Wessel van der Linden

    15. September 2018 um 19:29 Uhr


  • Dies ist, was die React-Dokumentation darüber sagt: „Das SyntheticEvent wird gepoolt. Das bedeutet, dass das SyntheticEvent-Objekt wiederverwendet wird und alle Eigenschaften aufgehoben werden, nachdem der Event-Callback aufgerufen wurde. Dies ist aus Leistungsgründen. Daher können Sie nicht darauf zugreifen das Ereignis asynchron.” Ich verstehe es nicht ganz, aber ich denke, dass React nach der ersten Verwendung alle Event-Eigenschaften verliert. Wenn Sie also die Methode ohne () => {return} übergeben, ruft sie die übergebene Methode auf, während die Komponente bereitgestellt wird, und verliert dann die Eigenschaften des Ereignisses. Wenn das jemand bestätigen kann, wäre ich dankbar.

    – Adam Orłowski

    18. September 2018 um 14:26 Uhr


  • @WesselvanderLinden Ich denke, das ist, dass bei der Verwendung von an array.map() Die Funktion erstellt viele gleiche Elemente, wenn das Element ohne einen eindeutigen Schlüssel, React nicht erkennen konnte, welches Kind das Ereignis ausgelöst hat, sodass es zu einem Absturz kommen kann. Daher wird die Verwendung der ES6-Pfeilfunktion automatisch binden this zum Unikat.

    – xgqfrms

    20. Dezember 2018 um 7:57 Uhr

  • Ich glaube, dass die vorgeschlagene Änderung sein muss onChange={() => this.handleCheckbox()}, wobei die Klammern hinzugefügt werden, um die Funktion aufzurufen. Ich hatte das gleiche Problem und das hat es auch für mich behoben (obwohl der Handler überhaupt nicht mehr funktioniert hat, bevor ich den zweiten Elternsatz hinzugefügt habe), aber ich wünschte, ich hätte verstanden, warum!

    – AnnieP

    13. Dezember 2019 um 19:23 Uhr

  • @AnnieP Vielleicht mussten Sie die Funktion aufrufen, weil sie eine Funktion zurückgibt? Das würde die Notwendigkeit zusätzlicher Klammern rechtfertigen ().

    – Adam Orłowski

    13. Dezember 2019 um 23:19 Uhr

Dies mag etwas spät sein, aber ich bin gerade auf dasselbe Problem gestoßen und habe es auf eine Weise gelöst, die meiner Meinung nach besser sein könnte als die Antwort von Adam Orlov. Ich glaube nicht, dass eine der beiden Antworten direkt auf die gestellte Frage anwendbar ist, aber dies taucht auf, wenn nach synthetischen Ereignissen und Kontrollkästchen gegoogelt wird, also ist es ein so guter Ort wie jeder andere …

Ich glaube, Adam hat Recht mit seiner Annahme, dass React im Wesentlichen alle Eigenschaften des SyntheticEvent-Objekts löschen wird (was Sinn macht, da React uns sagt, dass es das Objekt wiederverwendet).

Wenn Sie jedoch nicht das gesamte Objekt benötigen, ist das Aufrufen von event.persist() meiner Meinung nach nicht die beste Lösung, da gemäß der Dokumentationdie das Objekt aus dem Pool entfernt (vermutlich haben sie es aus gutem Grund dort abgelegt).

Wenn Sie asynchron auf die Ereigniseigenschaften zugreifen möchten, sollten Sie event.persist() für das Ereignis aufrufen, wodurch das synthetische Ereignis aus dem Pool entfernt wird und Verweise auf das Ereignis vom Benutzercode beibehalten werden können.

Wenn Sie stattdessen nur einen oder zwei Werte aus dem Ereignisobjekt benötigen, können Sie diese einfach lokalen Variablen zuweisen und dann die lokalen Variablen in Ihrer eigenen Funktion wie folgt referenzieren:

<input type="checkbox" onChange={(event) => {
    let checked = event.currentTarget.checked; //store whatever values we need from from the event here
    this._someOtherFunction(checked)
} />

Auf diese Weise müssen Sie Ihren Code in keiner Weise neu strukturieren, um zu vermeiden, dass asynchrone Vorgänge ausgeführt werden, die auf Ereignisdaten angewiesen sind, und Sie müssen sich auch keine Gedanken über potenzielle Auswirkungen auf die Leistung machen, da Sie React erlauben, damit zu tun, was es will der Eventpool.

Benutzer-Avatar
Eric Hendrix

Ähnliches Problem hier, obwohl mein Setup funktionale Komponente, Material UI ist <Textform /> Eingang.

Der Typ oben erwähnt event.persist();, danke, das hat bei mir funktioniert, aber der erste Vorschlag hatte keine merklichen Auswirkungen. Ich bin mir nicht sicher, ob das daran liegt, dass ich funktionale Komponenten und keine Klassenkomponenten verwende. (Ich verwende keine Klassenkomponenten mehr, nur mit Hooks funktionsfähig)

Beachten Sie auch die Warnhinweise, die zur Verwendung von event.persist() empfohlen werden. Mein Problem war, dass ich Formulareingaben mit onChange erfasste und Eingaben in meinem Zustand speicherte, nach etwa dem zweiten oder dritten Zeichen würde es Fehler auslösen und auch meine App zum Absturz bringen.

Vor:

    const handleChange = (e) => {
    
    setState((form) => ({
      ...form,
      [e.target.name]: e.target.value,
    }));
  };

Nach:

    const handleChange = (e) => {
    e.persist();
    setState((form) => ({
      ...form,
      [e.target.name]: e.target.value,
    }));
  };

Es scheint also, dass dies die richtige Lösung für ein ähnliches Problem ist, obwohl ich kein Kontrollkästchen verwendet habe, sondern eine Formulareingabe, eine Material-UI <TextField />. Ich kann die einzelne Zeile von entfernen

e.persist();

und der Code wird wieder fehlschlagen, fügen Sie ihn wieder hinzu, alles ist gut, kein Absturz, keine Warnungen.

Benutzer-Avatar
FSBALBÜNA

für diejenigen, die mit React Native auf dieses Problem gestoßen sind.

Ich stehe vor diesem Problem bei einer Navigation

PersonalProductsScreen.navigationOptions=({navigation})=>{
const handleEditButton=navigation.navigate.bind(this,"EditProduct")
return {
    headerTitle:"My Products",
    headerRight:<CustomHeaderButton 
    iconName="ios-add"
    title="Add"
    iconSize={26}
    color={colors.bright}
    onPress={handleEditButton}
    />
}

}

Achten Sie auf die Methode, die ich verwendet habe. Ich habe versucht, die Navigationsmethode zu binden.

Das ist der Refactor:

const handleAddButton=()=>navigation.navigate("EditProduct")

1109700cookie-checkWarnung: Dieses synthetische Ereignis wird aus Performance-Gründen wiederverwendet

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy