Reaktions-Hooks: Zugriff auf den aktuellen Status innerhalb eines Rückrufs

Lesezeit: 7 Minuten

Benutzer-Avatar
Stange

BEARBEITEN (22. Juni 2020): Da diese Frage ein erneutes Interesse hat, ist mir klar, dass es einige Verwirrung geben kann. Daher möchte ich hervorheben: Das Beispiel in der Frage ist als Spielzeugbeispiel gedacht. Es spiegelt das Problem nicht wider. Das Problem, das diese Frage ausgelöst hat, liegt in der Verwendung einer Bibliothek eines Drittanbieters (über die nur eine begrenzte Kontrolle besteht), die einen Rückruf als Argument für eine Funktion verwendet. Was ist der richtige Weg, um diesen Rückruf mit dem neuesten Status bereitzustellen. In Reaktionsklassen würde dies durch die Verwendung von erfolgen this. In React-Hooks ist der Zustand aufgrund der Art und Weise in den Funktionen von gekapselt React.useState()wenn ein Rückruf bekommt der Staat durch React.useState(), ist es veraltet (der Wert, als der Rückruf eingerichtet wurde). Aber wenn es setzt dem Zustand, hat er über das übergebene Argument Zugriff auf den neuesten Zustand. Dies bedeutet, dass wir möglicherweise den neuesten Status in einem solchen Rückruf mit React-Hooks von abrufen können Einstellung der Zustand soll derselbe sein wie er war. Das funktioniert, ist aber kontraintuitiv.

— Ursprüngliche Frage geht weiter unten —

Ich verwende React-Hooks und versuche, den Status innerhalb eines Callbacks zu lesen. Jedes Mal, wenn der Callback darauf zugreift, ist es auf seinen Standardwert zurückgesetzt.

Mit folgendem Code. Die Konsole druckt weiter Count is: 0 egal wie oft ich klicke.

function Card(title) {
  const [count, setCount] = React.useState(0)
  const [callbackSetup, setCallbackSetup] = React.useState(false)
  
  function setupConsoleCallback(callback) {
    console.log("Setting up callback")
    setInterval(callback, 3000)
  }

  function clickHandler() {
    setCount(count+1);
    if (!callbackSetup) {
      setupConsoleCallback(() => {console.log(`Count is: ${count}`)})
      setCallbackSetup(true)
    }
  }
  
  
  return (<div>
      Active count {count} <br/>
      <button onClick={clickHandler}>Increment</button>
    </div>);
  
}

const el = document.querySelector("#root");
ReactDOM.render(<Card title="Example Component" />, el);

Sie können diesen Code finden hier

Ich hatte kein Problem damit, den Status innerhalb eines Rückrufs festzulegen, nur beim Zugriff auf den neuesten Status.

Wenn ich raten müsste, würde ich denken, dass jede Zustandsänderung eine neue Instanz der Card-Funktion erstellt. Und dass sich der Rückruf auf den alten bezieht. Basierend auf der Dokumentation unter https://reactjs.org/docs/hooks-reference.html#functional-updates, hatte ich die Idee, setState im Callback aufzurufen und eine Funktion an setState zu übergeben, um zu sehen, ob ich von setState aus auf den aktuellen Status zugreifen kann. Ersetzen

setupConsoleCallback(() => {console.log(`Count is: ${count}`)})

mit

setupConsoleCallback(() => {setCount(prevCount => {console.log(`Count is: ${prevCount}`); return prevCount})})

Sie können diesen Code finden hier

Auch dieser Ansatz hat nicht funktioniert. EDIT: Eigentlich dieser zweite Ansatz tut Arbeit. Ich hatte nur einen Tippfehler in meinem Rückruf. Das ist der richtige Ansatz. Ich muss setState aufrufen, um auf den vorherigen Zustand zuzugreifen. Auch wenn ich nicht die Absicht habe, den Zustand festzulegen.

Ich habe das Gefühl, dass ich mit React-Klassen ähnliche Ansätze verfolgt habe, aber. Aus Gründen der Codekonsistenz muss ich bei React Effects bleiben.

Wie kann ich von einem Callback aus auf die neuesten Statusinformationen zugreifen?

  • Ich glaube nicht, dass es ein Duplikat von oben ist. Da es nicht um die Tatsacheneinstellung geht, ist der Zustand asynchron. Aber über den Staat bis in alle Ewigkeit in einem Rückruf veraltet sein. Jetzt, wo ich die Antwort herausgefunden habe, kann es sich jedoch um ein Duplikat von stackoverflow.com/questions/56782079/react-hooks-stale-state handeln. Ich denke jedoch, dass dies auf eine interessante Folge davon hinweist, wie Reaktionshaken den Status verwalten. nämlich, dass Sie eine Funktion aufrufen müssen, die den Zustand festlegt, um innerhalb eines Rückrufs auf den richtigen Zustand zuzugreifen. Und das gilt auch dann, wenn Sie nicht die Absicht haben, den Zustand zu ändern.

    – Stange

    9. September 2019 um 4:02 Uhr

  • ja, du hast recht, es geht darum, wie Funktionsschließung funktioniert. hier ist eines der Themen zu diesem stackoverflow.com/questions/57471987/…

    – Himmelsjunge

    9. September 2019 um 4:42 Uhr


  • Vielleicht hilft dieser Blog von Dan Abramov: overreacted.io/making-setinterval-declarative-with-react-hooks, erklärt es, warum das Mischen von Hooks und setInterval wirklich verwirrend ist und zunächst nicht zu funktionieren scheint. TL:DR im Grunde wegen der Schließung müssen Sie den Rückruf mit dem nächsten Zustandswert “erneut einschließen”.

    – Zeichnete Reese

    9. September 2019 um 5:01 Uhr


  • Ja, ich dachte, es war etwas in dieser Richtung, als ich gebunden hätte this zum Rückruf, wenn ich Klassen verwendet habe, aber nicht sehen konnte, wie man es mit Effekten macht. Ich habe Ansätze wie das Einschließen von Gettern in die Zustandsvariable als Argument für den Rückruf ausprobiert. Aber nichts funktionierte. Jedenfalls ist mir nach Überprüfung aller Links, die alle geteilt haben, immer noch etwas nicht klar. Gibt es keine Möglichkeit, den Zustand der Komponente einfach aus einem anderen Kontext zu lesen, als durch Aufrufen ihrer Zustandseinstellungsfunktion (insbesondere wenn ich dies tue nicht möchte seinen Zustand ändern)?

    – Stab

    9. September 2019 um 6:28 Uhr

  • In einigen Szenarien wäre es nicht richtiger, die zu verwenden useReducer() Haken dafür? In meinem Fall habe ich einen Rückruf an eine Bibliothek übergeben, die bei Nachrichten von vom Server gesendeten Ereignissen ausgelöst wird. Wenn eine Nachricht beim Client ankommt, wird der Rückruf ausgelöst und an die vorhandene gesendet messages Zustand.

    – Gjert

    22. August 2020 um 7:39 Uhr


Benutzer-Avatar
Aminadav Glickshtein

Aktualisierung Juni 2021:

Verwenden Sie das NPM-Modul react-usestateref um immer den neuesten Statuswert zu erhalten. Es ist vollständig abwärtskompatibel mit React useState API.

Beispielcode zur Verwendung:

import useState from 'react-usestateref';

const [count, setCount, counterRef] = useState(0);

console.log(couterRef.current); // it will always have the latest state value
setCount(20);
console.log(counterRef.current);

Das NPM-Paket reagieren-useStateRef ermöglicht den Zugriff auf den neuesten Status (wie z ref), durch die Nutzung useState.

Update Dezember 2020:

Um genau dieses Problem zu lösen, habe ich dafür ein Reaktionsmodul erstellt. react-usestateref (useStateRef reagieren). Einsatzbeispiel:

var [state, setState, ref] = useState(0);

Es funktioniert genau wie useState aber zusätzlich gibt es Ihnen den aktuellen Stand unter ref.current

Mehr erfahren:

Ursprüngliche Antwort

Sie können den neuesten Wert abrufen, indem Sie die verwenden setState

Zum Beispiel:

var [state, setState] = useState(defaultValue);

useEffect(() => {
   var updatedState;
   setState(currentState => { // Do not change the state by getting the updated state
      updateState = currentState;
      return currentState;
   })
   alert(updateState); // the current state.
})

  • Ich denke, das ist perfekt!. Anstatt eine Objektinstanz und einen useRef-Hook zu erstellen. 🙂

    – Keval Bhatt

    25. August 2020 um 6:19 Uhr


  • ist die syntax im eg-abschnitt korrekt?

    – Praveen MP

    16. Februar 2021 um 18:14 Uhr

  • Danke für diese Erklärung! Hat es mir total verdeutlicht.

    – wlabs

    9. Januar um 5:52

  • Aber wenn die Referenz immer noch dieselbe ist, wie wird React wissen, dass sie sich geändert hat?

    – Auine

    23. Januar um 11:11 Uhr


Sie können auf die neuesten zugreifen state in setState Rückrufen. Aber die Absicht ist nicht klar, wir wollen es nie setState In diesem Fall kann es andere Personen verwirren, wenn sie Ihren Code lesen. Vielleicht möchten Sie es in einen anderen Haken packen, der das, was Sie wollen, besser ausdrücken kann

function useExtendedState<T>(initialState: T) {
  const [state, setState] = React.useState<T>(initialState);
  const getLatestState = () => {
    return new Promise<T>((resolve, reject) => {
      setState((s) => {
        resolve(s);
        return s;
      });
    });
  };

  return [state, setState, getLatestState] as const;
}

Verwendungszweck

const [counter, setCounter, getCounter] = useExtendedState(0);

...

getCounter().then((counter) => /* ... */)

// you can also use await in async callback
const counter = await getCounter();

Live-Demo

Bearbeiten Sie GetLatestState

Benutzer-Avatar
Skyline R

Ich hatte ein ähnliches Problem, aber in meinem Fall habe ich Redux mit Hooks verwendet und auch den Status in derselben Komponente nicht verändert. Ich hatte eine Methode, die beim Rückruf den Zustandswert verwendete score und es (Rückruf) hatte alte Kerbe. Also meine Lösung dafür ist ganz einfach. Es ist nicht so elegant wie die vorherigen, aber in meinem Fall hat es funktioniert, also stelle ich es hier in der Hoffnung, dass es jemandem helfen wird.

const score = useSelector((state) => state.score);
const scoreRef = useRef(score);

useEffect(() => {
    scoreRef.current = score ;
}, [score])

Allgemeine Idee ist, den neuesten Zustand in ref zu speichern 🙂

Benutzer-Avatar
T. Dayya

Die einzige Methode, die ich kenne, besteht darin, die Funktion setState (current_value => …) aufzurufen und den current_value in Ihrer Logik zu verwenden. Stellen Sie nur sicher, dass Sie es zurücksenden. Ex:

const myPollingFunction = () => {
    setInterval(() => {
        setState(latest_value => {
            // do something with latest_value
            return latest_value;    
        }
    }, 1000);
};

1010040cookie-checkReaktions-Hooks: Zugriff auf den aktuellen Status innerhalb eines Rückrufs

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

Privacy policy