Powiedzmy, że mam 3 wejścia: rate, sendAmount i acceptAmount. Umieściłem te 3 wejścia na różnicowych parametrach useEffect. Zasady są następujące:
- Jeśli wartość sendAmount uległa zmianie, obliczam
receiveAmount = sendAmount * rate
- Jeśli wartość otrzymanej kwoty uległa zmianie, obliczam
sendAmount = receiveAmount / rate
- Jeśli kurs się zmienił, obliczam
receiveAmount = sendAmount * rate
kiedysendAmount > 0
lub obliczamsendAmount = receiveAmount / rate
kiedyreceiveAmount > 0
Oto kodyandbox https://codesandbox.io/s/pkl6vn7x6j, aby zademonstrować problem.
Czy istnieje sposób na porównanie oldValues
i newValues
polubienie componentDidUpdate
zamiast tworzenia 3 programów obsługi dla tego przypadku?
Dzięki
Oto moje ostateczne rozwiązanie z usePrevious
https://codesandbox.io/s/30n01w2r06
W tym przypadku nie mogę użyć wielu, useEffect
ponieważ każda zmiana prowadzi do tego samego połączenia sieciowego. Dlatego też używam changeCount
do śledzenia zmian. Jest to changeCount
również pomocne w śledzeniu zmian tylko z lokalnego, więc mogę zapobiec niepotrzebnym połączeniom sieciowym z powodu zmian z serwera.
źródło
Odpowiedzi:
Możesz napisać niestandardowy punkt zaczepienia, który zapewni ci poprzednie właściwości za pomocą useRef
a następnie użyj go w
useEffect
Jednak jest to jaśniejsze i prawdopodobnie lepsze i bardziej przejrzyste do odczytania i zrozumienia, jeśli używasz dwóch
useEffect
osobno dla każdego identyfikatora zmiany, który chcesz przetwarzać osobnoźródło
useEffect
połączeń oddzielnie. Nie wiedziałem, że możesz go używać wiele razy!useEffect
brakuje zależnościprevAmount
O ile ktoś szuka wersji do wykorzystania w języku TypeScript
źródło
const usePrevious = <T extends any>(...
aby interpreter zobaczył, że <T> to nie JSX i jest to ogólne ograniczenie<T extends {}>
nie zadziała. Wydaje się, że to działa dla mnie, ale próbuję zrozumieć złożoność korzystania z niego w ten sposób..tsx
pliki zawierają jsx, co ma być identyczne z html. Możliwe, że rodzaj ogólny<T>
jest niezamkniętym znacznikiem komponentu.Missing return type on function.eslint(@typescript-eslint/explicit-function-return-type)
Opcja 1 - useCompare hook
Porównanie bieżącej wartości z poprzednią wartością jest powszechnym wzorcem i uzasadnia własny niestandardowy punkt zaczepienia, który ukrywa szczegóły implementacji.
Próbny
Opcja 2 - uruchom useEffect po zmianie wartości
Próbny
źródło
Właśnie opublikowałem odpowiedź -delta, która rozwiązuje dokładnie tego rodzaju scenariusz. Moim zdaniem
useEffect
ma zbyt wiele obowiązków.Obowiązki
Object.is
Zerwanie odpowiedzialności
react-delta
dzieliuseEffect
obowiązki na kilka mniejszych haczyków.Odpowiedzialność nr 1
usePrevious(value)
useLatest(value)
useDelta(value, options)
useDeltaArray(valueArray, options)
useDeltaObject(valueObject, options)
some(deltaArray)
every(deltaArray)
Odpowiedzialność nr 2
useConditionalEffect(callback, boolean)
Z mojego doświadczenia wynika, że to podejście jest bardziej elastyczne, przejrzyste i zwięzłe niż
useEffect
/useRef
rozwiązania.źródło
Ponieważ stan nie jest ściśle powiązany z instancją komponentu w komponentach funkcjonalnych, nie można osiągnąć poprzedniego stanu
useEffect
bez wcześniejszego zapisania go, na przykład za pomocąuseRef
. Oznacza to również, że aktualizacja stanu została prawdopodobnie nieprawidłowo zaimplementowana w niewłaściwym miejscu, ponieważ poprzedni stan jest dostępny wsetState
funkcji aktualizatora.Jest to dobry przypadek użycia,
useReducer
który zapewnia sklep podobny do Redux i pozwala na implementację odpowiedniego wzorca. Aktualizacje stanu są wykonywane jawnie, więc nie ma potrzeby sprawdzania, która właściwość stanu jest aktualizowana; widać to już po wysłanej akcji.Oto przykład, jak to może wyglądać:
źródło
sendAmount
itp. Asynchronicznie zamiast je obliczać, prawda? To się bardzo zmienia. Można to zrobić,useReduce
ale może to być trudne. Jeśli zajmowałeś się Reduxem, możesz wiedzieć, że operacje asynchroniczne nie są tam proste. github.com/reduxjs/redux-thunk to popularne rozszerzenie dla Redux, które pozwala na akcje asynchroniczne. Oto demo, które rozszerza useReducer o ten sam wzorzec (useThunkReducer) , codeandbox.io/s/6z4r79ymwr . Zauważ, że wysłana funkcja jest takaasync
, że możesz tam wykonywać żądania (skomentowane).Użycie Ref wprowadzi do aplikacji nowy rodzaj błędu.
Zobaczmy ten przypadek, korzystając z
usePrevious
wcześniejszego komentarza:Jak widać tutaj, nie aktualizujemy wewnętrznego,
ref
ponieważ używamyuseEffect
źródło
state
... a nieprops
... kiedy zależy ci na starych rekwizytach, wtedy wystąpi błąd.Dla naprawdę prostego porównania rekwizytów możesz użyć useEffect, aby łatwo sprawdzić, czy właściwość została zaktualizowana.
useEffect uruchomi wtedy Twój kod tylko wtedy, gdy właściwość ulegnie zmianie.
źródło
prop
zmianach nie będziesz w stanie~ do stuff here ~
setHasPropChanged(false)
pod koniec,~ do stuff here ~
aby „zresetować” swój stan. (Ale to by się zresetowało w dodatkowym wydaniu)Wychodząc od zaakceptowanej odpowiedzi, alternatywne rozwiązanie, które nie wymaga niestandardowego zaczepu:
źródło
useRef
nieuserRef
. Zapomniałem użyć prąduprevAmount.current
Oto niestandardowy hak, którego używam, a który moim zdaniem jest bardziej intuicyjny niż używanie
usePrevious
.Używałbyś
useTransition
w następujący sposób.Mam nadzieję, że to pomoże.
źródło