React: Fehler: Nicht verwandte Statusaktualisierung in onKeyDown blockiert onChange und bricht die kontrollierte Komponente

Erstellt am 9. Juli 2020  ·  3Kommentare  ·  Quelle: facebook/react

Hallo, ich verwende den eingangsgesteuerten Modus und abonniere das Ereignis onKeyDown und onChange . Es wird ein Effekt ausgelöst, wenn der Benutzer Leerzeichen eingibt. Der Platz wird jedoch nicht auf dem Bildschirm angezeigt. Ist dies ein Fehler bei React oder stimmt etwas nicht mit der Art und Weise, wie ich es benutze? Aber onKeyUp abonnieren ist normal. Das ist verwirrt.

Reaktionsversion: 16.13.1 und alt

Schritte zum Reproduzieren

  1. Raum betreten
  2. Das Eingabeelement zeigt keinen Platz auf dem Bildschirm an

Link zum Codebeispiel:

import React, { useState,useEffect } from 'react'

const App = () => {
  const [count, setCount] = useState(0)
  const [value, setValue] = useState('')
  const [code, setCode] = useState('add')

  useEffect(() => {
    if (code === 'add') {
      setCount(c => c + 1)
    } else {
      setCount(c => c - 1)
    }
  }, [code, setCount])

  const keyDown = e => {
    if (e.keyCode === 32) {
      console.log('space~')
      if (code === 'add') {
        setCode('minus')
      } else {
        setCode('add')
      }
    }
  }

  const handleChange = e => {
    setValue(e.target.value)
  }

  return (
    <div>
      <div>{count}</div>
      <br />
      <input onKeyDown={keyDown} value={value} onChange={handleChange} />
    </div>
  )
}

export default App

Das aktuelle Verhalten

Das Eingabeelement kann das Leerzeichen nicht empfangen

Das erwartete Verhalten

Eingabeelement kann den Raum empfangen

DOM Unconfirmed Bug

Alle 3 Kommentare

Es sieht so aus, als ob die Statusaktualisierung im onKeyDown -Handler das Ereignis unterbricht und verhindert, dass der onChange -Handler aufgerufen wird. Da kontrollierte Komponenten nur das anzeigen, was Sie ihnen sagen (der Status value in Ihrem Beispiel), wird das Leerzeichen nie angezeigt.

Das sieht für mich nach einem Fehler im Zusammenspiel dieser beiden Ereignisse aus.

cc @trueadm @gaearon für ihre Erfahrung mit Veranstaltungssystemen

Hallo, ich bin neu hier und versuche, die React-Architektur zu lernen.

@bvaughn Hier ist etwas, das ich über das Problem gefunden habe.

onKeyDown Ereignis onChange sondern wird früher ausgelöst, als die Eingabe geändert wird. Grundsätzlich geht onKeyDown früher als onChange da die Texteingabe in onKeyUp .

In diesem speziellen Fall besteht das Problem darin, dass innerhalb von keyDown , wenn setCode anruft, beim ersten dispatchAction _Fiber_ memoizedState ohne das neue Zeichen (offensichtlich) vorhanden ist. und e die hinzugefügt werden. Am Ende wird das neue Zeichen zur Eingabe hinzugefügt. Dann useEffect() Trigger dispatchAction wieder innerhalb der _same warteschlange_ (nicht sicher , ob es der Warteschlange) , aber es nicht zu aktualisierten Requisiten weiß nichts. Wenn es also commitRoot , werden pendingProps wiederhergestellt, die memoizedState identisch sind. Kurz gesagt, das Zeichen (in diesem Beispiel Leerzeichen) wird hinzugefügt und der alte Zustand wird sofort ohne das neue Zeichen (Leerzeichen) wiederhergestellt, sodass es so aussieht, als würde nichts hinzugefügt.

Als Beispiel für die Nichtverwendung von _same queue_ (?) In diesem Beispiel:

useEffect(() => {
    if (code === 'add') {
      setCount(c => c + 1)
    } else {
      setCount(c => c - 1)
    }
  }, [code, setCount])

könnte geändert werden zu:

useEffect(() => {
    if (code === 'add') {
      setTimeout(() => setCount(c => c + 1), 0)
    } else {
      setTimeout(() => setCount(c => c - 1), 0)
    }
  }, [code, setCount])

und es wird funktionieren.

Ich hoffe es macht Sinn.

Das gleiche Problem ist aufgetreten, als ich meinen setState-Aufruf in aa setTimeout im Keydown-Handler eingeschlossen habe.

Ich bin gespannt, ob dies in React unter der Haube anders funktionieren sollte oder ob dieser Fehler auf einen größeren Fehler oder ein schlechtes Muster auf der Entwicklerseite hinweist.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen