Angenommen, ich habe drei Eingaben: rate, sendAmount und receiveAmount. Ich habe diese 3 Eingänge auf useEffect diffing params gesetzt. Die Regeln sind:
- Wenn sendAmount geändert wurde, berechne ich
receiveAmount = sendAmount * rate
- Wenn receiveAmount geändert wurde, berechne ich
sendAmount = receiveAmount / rate
- Wenn sich die Rate ändert, berechne ich
receiveAmount = sendAmount * rate
wannsendAmount > 0
odersendAmount = receiveAmount / rate
wannreceiveAmount > 0
Hier ist die Codesandbox https://codesandbox.io/s/pkl6vn7x6j , um das Problem zu demonstrieren.
Gibt es eine Möglichkeit, das oldValues
und newValues
dergleichen zu vergleichen, componentDidUpdate
anstatt 3 Handler für diesen Fall zu erstellen?
Vielen Dank
Hier ist meine endgültige Lösung mit usePrevious
https://codesandbox.io/s/30n01w2r06
In diesem Fall kann ich nicht mehrere verwenden, useEffect
da jede Änderung zu demselben Netzwerkanruf führt. Deshalb changeCount
verfolge ich die Änderung auch. Dies ist changeCount
auch hilfreich, um Änderungen nur von lokal zu verfolgen, damit ich unnötige Netzwerkanrufe aufgrund von Änderungen vom Server verhindern kann.
quelle
Antworten:
Mit useRef können Sie einen benutzerdefinierten Hook schreiben, um frühere Requisiten bereitzustellen
und dann verwenden Sie es in
useEffect
Es ist jedoch klarer und wahrscheinlich besser und klarer zu lesen und zu verstehen, wenn Sie zwei
useEffect
separat für jede Änderungs-ID verwenden, die Sie separat verarbeiten möchtenquelle
useEffect
Anrufe getrennt zu verwenden. Wusste nicht, dass du es mehrmals benutzen kannst!useEffect
fehlenden AbhängigkeitenprevAmount
Falls jemand nach einer TypeScript-Version von usePrevious sucht:
quelle
const usePrevious = <T extends any>(...
damit der Interpreter denkt, dass <T> nicht JSX ist und eine generische Einschränkung darstellt<T extends {}>
nicht funktioniert. Es scheint für mich zu funktionieren, aber ich versuche zu verstehen, wie komplex es ist, es so zu verwenden..tsx
Dateien enthalten jsx, das mit HTML identisch sein soll. Es ist möglich, dass das Generikum<T>
ein nicht geschlossenes Komponenten-Tag ist.Missing return type on function.eslint(@typescript-eslint/explicit-function-return-type)
Option 1 - useCompare-Hook
Das Vergleichen eines aktuellen Werts mit einem vorherigen Wert ist ein gängiges Muster und rechtfertigt einen eigenen benutzerdefinierten Hook, der Implementierungsdetails verbirgt.
Demo
Option 2 - Verwenden Sie useEffect, wenn sich der Wert ändert
Demo
quelle
Ich habe gerade React-Delta veröffentlicht , das genau diese Art von Szenario löst. Meiner Meinung nach,
useEffect
hat zu viele Verantwortlichkeiten.Verantwortlichkeiten
Object.is
Verantwortlichkeiten auflösen
react-delta
brichtuseEffect
die Verantwortung in mehrere kleinere Haken.Verantwortung # 1
usePrevious(value)
useLatest(value)
useDelta(value, options)
useDeltaArray(valueArray, options)
useDeltaObject(valueObject, options)
some(deltaArray)
every(deltaArray)
Verantwortung # 2
useConditionalEffect(callback, boolean)
Nach meiner Erfahrung ist dieser Ansatz flexibler, sauberer und prägnanter als
useEffect
/useRef
Lösungen.quelle
Da der Status in Funktionskomponenten nicht eng mit der Komponenteninstanz gekoppelt ist, kann der vorherige Status nicht erreicht werden,
useEffect
ohne ihn zuerst zu speichern, z. B. mituseRef
. Dies bedeutet auch, dass die Statusaktualisierung möglicherweise falsch an einer falschen Stelle implementiert wurde, da der vorherige Status darin verfügbar istsetState
Statusaktualisierung Updater-Funktion .Dies ist ein guter Anwendungsfall für
useReducer
den ein Redux-ähnlicher Speicher bereitgestellt wird und der die Implementierung eines entsprechenden Musters ermöglicht. Statusaktualisierungen werden explizit durchgeführt, sodass nicht herausgefunden werden muss, welche Statuseigenschaft aktualisiert wird. Dies geht bereits aus der versendeten Aktion hervor.Hier ist ein Beispiel, wie es aussehen könnte:
quelle
sendAmount
usw. asynchron abrufen möchten , anstatt sie zu berechnen, oder? Das ändert sich sehr. Es ist möglich, dies zu tunuseReduce
, kann aber schwierig sein. Wenn Sie sich zuvor mit Redux befasst haben, wissen Sie möglicherweise, dass asynchrone Vorgänge dort nicht einfach sind. github.com/reduxjs/redux-thunk ist eine beliebte Erweiterung für Redux, die asynchrone Aktionen ermöglicht. Hier ist eine Demo, die useReducer mit demselben Muster (useThunkReducer), Codesandbox.io/s/6z4r79ymwr , erweitert . Beachten Sie, dass die versendete Funktion lautetasync
, dass Sie dort Anforderungen ausführen können (kommentiert).Die Verwendung von Ref führt zu einer neuen Art von Fehler in der App.
Sehen wir uns diesen Fall mit
usePrevious
dem zuvor kommentierten an:Wie wir hier sehen können, aktualisieren
ref
wir das interne nicht, weil wir es verwendenuseEffect
quelle
state
... und nicht dasprops
... Wenn Sie sich für die alten Requisiten interessieren, wird ein Fehler auftreten.Für einen wirklich einfachen Vergleich der Requisiten können Sie mit useEffect leicht überprüfen, ob eine Requisite aktualisiert wurde.
useEffect führt Ihren Code dann nur aus, wenn sich die Requisite ändert.
quelle
prop
Änderungen können Sie nicht~ do stuff here ~
setHasPropChanged(false)
am Ende von anrufen, um~ do stuff here ~
Ihren Status zurückzusetzen. (Aber dies würde in einem zusätzlichen Renderer zurückgesetzt)Die akzeptierte Antwort ist eine alternative Lösung, für die kein benutzerdefinierter Hook erforderlich ist:
quelle
useRef
nichtuserRef
. Ich habe vergessen, Strom zu verwendenprevAmount.current
Hier ist ein benutzerdefinierter Hook, den ich verwende und der meiner Meinung nach intuitiver ist als die Verwendung
usePrevious
.Sie würden
useTransition
wie folgt verwenden.Hoffentlich hilft das.
quelle