React Hooks wird useState
zum Einstellen des Komponentenzustands eingeführt. Aber wie kann ich Hooks verwenden, um den Rückruf wie folgt zu ersetzen:
setState(
{ name: "Michael" },
() => console.log(this.state)
);
Ich möchte etwas tun, nachdem der Status aktualisiert wurde.
Ich weiß, dass ich useEffect
die zusätzlichen Dinge verwenden kann, aber ich muss den vorherigen Statuswert überprüfen, für den ein Bitcode erforderlich ist. Ich suche eine einfache Lösung, die mit useState
Haken verwendet werden kann.
Antworten:
Sie müssen
useEffect
Haken verwenden, um dies zu erreichen.const [counter, setCounter] = useState(0); const doSomething = () => { setCounter(123); } useEffect(() => { console.log('Do something after counter has changed', counter); }, [counter]);
quelle
console.log
beim ersten Rendern sowie allecounter
Zeitänderungen aus. Was ist, wenn Sie erst etwas tun möchten, nachdem der Status aktualisiert wurde, aber nicht beim ersten Rendern, da der Anfangswert festgelegt ist? Ich denke, Sie könnten den Wert eincheckenuseEffect
und entscheiden, ob Sie dann etwas tun möchten. Wäre das eine bewährte Methode?useEffect
beim ersten Rendern ausgeführt wird, können Sie einen benutzerdefiniertenuseEffect
Hook erstellen , der beim ersten Rendern nicht ausgeführt wird. Um einen solchen Hook zu erstellen, können Sie diese Frage überprüfen: stackoverflow.com/questions/53253940/…Warning: State updates from the useState() and useReducer() Hooks don't support the second callback argument. To execute a side effect after rendering, declare it in the component body with useEffect().
Wenn Sie den vorherigen Status aktualisieren möchten, können Sie dies in Hooks tun:
const [count, setCount] = useState(0); setCount(previousCount => previousCount + 1);
quelle
setCounter
du meinstsetCount
useEffect
, Dass nur Brände auf Zustand Updates :const [state, setState] = useState({ name: "Michael" }) const isFirstRender = useRef(true) useEffect(() => { if (!isFirstRender.current) { console.log(state) // do something after state has updated } }, [state]) useEffect(() => { isFirstRender.current = false // toggle flag after first render/mounting }, [])
Oben wird der
setState
Rückruf am besten nachgeahmt und nicht für den Anfangszustand ausgelöst. Sie können einen benutzerdefinierten Hook daraus extrahieren:function useEffectUpdate(effect, deps) { const isFirstRender = useRef(true) useEffect(() => { if (!isFirstRender.current) { effect() } }, deps) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { isFirstRender.current = false; }, []); } // ... Usage inside component useEffectUpdate(() => { console.log(state) }, [state])
quelle
useState
Kann implementiert werden , um einen Rückruf wiesetState
in Klassen zu erhalten.Ich denke, die Verwendung
useEffect
ist kein intuitiver Weg.Ich habe dafür einen Wrapper erstellt. In diesem benutzerdefinierten Hook können Sie Ihren Rückruf an
setState
Parameter anstelle vonuseState
Parameter senden .Ich habe gerade eine Typescript-Version erstellt. Wenn Sie dies in Javascript verwenden müssen, entfernen Sie einfach eine Typennotation aus dem Code.
Verwendung
const [state, setState] = useStateCallback(1); setState(2, (n) => { console.log(n) // 2 });
Erklärung
import { SetStateAction, useCallback, useEffect, useRef, useState } from 'react'; type Callback<T> = (value?: T) => void; type DispatchWithCallback<T> = (value: T, callback?: Callback<T>) => void; function useStateCallback<T>(initialState: T | (() => T)): [T, DispatchWithCallback<SetStateAction<T>>] { const [state, _setState] = useState(initialState); const callbackRef = useRef<Callback<T>>(); const isFirstCallbackCall = useRef<boolean>(true); const setState = useCallback((setStateAction: SetStateAction<T>, callback?: Callback<T>): void => { callbackRef.current = callback; _setState(setStateAction); }, []); useEffect(() => { if (isFirstCallbackCall.current) { isFirstCallbackCall.current = false; return; } callbackRef.current?.(state); }, [state]); return [state, setState]; } export default useStateCallback;
Nachteil
Wenn die übergebene Pfeilfunktion auf eine variable äußere Funktion verweist, erfasst sie den aktuellen Wert und keinen Wert, nachdem der Status aktualisiert wurde. Im obigen Verwendungsbeispiel gibt console.log (Status) 1 statt 2 aus.
quelle
state
bezieht sich der noch auf den vorherigen, wenn Callback aufgerufen wird. Ist es nicht?Ihre Frage ist sehr gültig. Lassen Sie mich Ihnen sagen, dass useEffect standardmäßig einmal ausgeführt wird und jedes Mal, wenn sich das Abhängigkeitsarray ändert.
Überprüfen Sie das folgende Beispiel:
import React,{ useEffect, useState } from "react"; const App = () => { const [age, setAge] = useState(0); const [ageFlag, setAgeFlag] = useState(false); const updateAge = ()=>{ setAgeFlag(false); setAge(age+1); setAgeFlag(true); }; useEffect(() => { if(!ageFlag){ console.log('effect called without change - by default'); } else{ console.log('effect called with change '); } }, [ageFlag,age]); return ( <form> <h2>hooks demo effect.....</h2> {age} <button onClick={updateAge}>Text</button> </form> ); } export default App;
Wenn Sie möchten, dass der setState-Rückruf mit den Hooks ausgeführt wird, verwenden Sie die Flag-Variable und geben Sie den IF IF-ODER-IF-Block in useEffect an, damit nur dieser Codeblock ausgeführt wird, wenn diese Bedingungen erfüllt sind. Wie auch immer, der Effekt wird ausgeführt, wenn sich das Abhängigkeitsarray ändert, aber der IF-Code innerhalb des Effekts wird nur unter diesen bestimmten Bedingungen ausgeführt.
quelle
setState()
Änderungen am Komponentenstatus in die Warteschlange stellen und React mitteilen, dass diese Komponente und ihre untergeordneten Komponenten mit dem aktualisierten Status neu gerendert werden müssen.Die setState-Methode ist asynchron und gibt in der Tat kein Versprechen zurück. In Fällen, in denen eine Funktion aktualisiert oder aufgerufen werden soll, kann die Funktion in der setState-Funktion als zweites Argument als Rückruf bezeichnet werden. In Ihrem obigen Fall haben Sie beispielsweise eine Funktion als setState-Rückruf aufgerufen.
setState( { name: "Michael" }, () => console.log(this.state) );
Der obige Code funktioniert gut für Klassenkomponenten, aber im Fall von Funktionskomponenten können wir die setState-Methode nicht verwenden, und dies können wir den use-Effekt-Hook verwenden, um das gleiche Ergebnis zu erzielen.
Die offensichtliche Methode, die in den Sinn kommt, ist, dass ypu mit useEffect verwendet werden kann:
const [state, setState] = useState({ name: "Michael" }) useEffect(() => { console.log(state) // do something after state has updated }, [state])
Dies würde jedoch auch beim ersten Rendern ausgelöst, sodass wir den Code wie folgt ändern können, um das erste Renderereignis zu überprüfen und das Status-Rendering zu vermeiden. Daher kann die Implementierung folgendermaßen erfolgen:
Wir können den Benutzer-Hook hier verwenden, um das erste Rendering zu identifizieren.
Mit dem useRef-Hook können wir veränderbare Variablen in Funktionskomponenten erstellen. Dies ist nützlich, um auf DOM-Knoten / React-Elemente zuzugreifen und veränderbare Variablen zu speichern, ohne ein erneutes Rendern auszulösen.
const [state, setState] = useState({ name: "Michael" }); const firstTimeRender = useRef(true); useEffect(() => { if (!firstTimeRender.current) { console.log(state); } }, [state]) useEffect(() => { firstTimeRender.current = false }, [])
quelle
Ich hatte einen Anwendungsfall, in dem ich einen API-Aufruf mit einigen Parametern tätigen wollte, nachdem der Status festgelegt wurde. Ich wollte diese Parameter nicht als meinen Status festlegen, also habe ich einen benutzerdefinierten Hook erstellt und hier ist meine Lösung
import { useState, useCallback, useRef, useEffect } from 'react'; import _isFunction from 'lodash/isFunction'; import _noop from 'lodash/noop'; export const useStateWithCallback = initialState => { const [state, setState] = useState(initialState); const callbackRef = useRef(_noop); const handleStateChange = useCallback((updatedState, callback) => { setState(updatedState); if (_isFunction(callback)) callbackRef.current = callback; }, []); useEffect(() => { callbackRef.current(); callbackRef.current = _noop; // to clear the callback after it is executed }, [state]); return [state, handleStateChange]; };
quelle
UseEffect ist die primäre Lösung. Wie Darryl bereits erwähnt hat, wird die Komponente beim Initialisierungsprozess ausgeführt, wenn useEffect verwendet und der Status als zweiter Parameter übergeben wird. Wenn Sie nur möchten, dass die Rückruffunktion mit dem Wert des aktualisierten Status ausgeführt wird, können Sie eine lokale Konstante festlegen und diese sowohl im setState als auch im Rückruf verwenden.
const [counter, setCounter] = useState(0); const doSomething = () => { const updatedNumber = 123; setCounter(updatedNumber); // now you can "do something" with updatedNumber and don't have to worry about the async nature of setState! console.log(updatedNumber); }
quelle