Disons que j'ai 3 entrées: rate, sendAmount et receiveAmount. Je mets que 3 entrées sur useEffect des paramètres différents. Les règles sont:
- Si sendAmount a changé, je calcule
receiveAmount = sendAmount * rate
- Si receiveAmount a changé, je calcule
sendAmount = receiveAmount / rate
- Si le taux a changé, je calcule
receiveAmount = sendAmount * rate
quandsendAmount > 0
ou je calculesendAmount = receiveAmount / rate
quandreceiveAmount > 0
Voici le codeandbox https://codesandbox.io/s/pkl6vn7x6j pour illustrer le problème.
Existe-t-il un moyen de comparer les oldValues
et les newValues
autres au componentDidUpdate
lieu de créer 3 gestionnaires pour ce cas?
Merci
Voici ma solution finale avec usePrevious
https://codesandbox.io/s/30n01w2r06
Dans ce cas, je ne peux pas utiliser plusieurs useEffect
car chaque changement conduit au même appel réseau. C'est pourquoi j'utilise également changeCount
pour suivre le changement. Cela est changeCount
également utile pour suivre les modifications à partir du local uniquement, afin que je puisse éviter les appels réseau inutiles en raison des modifications du serveur.
la source
Réponses:
Vous pouvez écrire un hook personnalisé pour vous fournir des accessoires précédents en utilisant useRef
puis utilisez-le dans
useEffect
Cependant, il est plus clair et probablement meilleur et plus clair à lire et à comprendre si vous en utilisez deux
useEffect
séparément pour chaque identifiant de modification que vous souhaitez traiter séparémentla source
useEffect
appels séparément. Je ne savais pas que vous pouviez l'utiliser plusieurs fois!useEffect
les dépendances manquantesprevAmount
Dans le cas où quiconque recherche une version d'utilisation de TypeScript
la source
const usePrevious = <T extends any>(...
faire en sorte que l'interpréteur voit que <T> n'est pas JSX et est une restriction générique<T extends {}>
ne fonctionnera pas. Cela semble fonctionner pour moi, mais j'essaie de comprendre la complexité de l'utiliser comme ça..tsx
les fichiers contiennent jsx qui est censé être identique à html. Il est possible que le générique<T>
soit une balise de composant non fermée.Missing return type on function.eslint(@typescript-eslint/explicit-function-return-type)
Option 1 - crochet useCompare
La comparaison d'une valeur actuelle à une valeur précédente est un modèle courant et justifie un hook personnalisé qui cache les détails de l'implémentation.
Démo
Option 2 - Exécutez useEffect lorsque la valeur change
Démo
la source
Je viens de publier react-delta qui résout ce genre de scénario exact. À mon avis,
useEffect
a trop de responsabilités.Responsabilités
Object.is
Rompre les responsabilités
react-delta
diviseuseEffect
les responsabilités en plusieurs petits crochets.Responsabilité # 1
usePrevious(value)
useLatest(value)
useDelta(value, options)
useDeltaArray(valueArray, options)
useDeltaObject(valueObject, options)
some(deltaArray)
every(deltaArray)
Responsabilité # 2
useConditionalEffect(callback, boolean)
D'après mon expérience, cette approche est plus flexible, propre et concise que
useEffect
/useRef
solutions.la source
Étant donné que l'état n'est pas étroitement associé à l'instance de composant dans les composants fonctionnels, l'état précédent ne peut pas être atteint
useEffect
sans l'enregistrer au préalable, par exemple avecuseRef
. Cela signifie également que la mise à jour de l'état a peut-être été mal implémentée au mauvais endroit car l'état précédent est disponible dans lasetState
fonction de mise à jour.C'est un bon cas d'utilisation pour
useReducer
lequel fournit un stockage de type Redux et permet d'implémenter le modèle respectif. Les mises à jour d'état sont effectuées explicitement, il n'est donc pas nécessaire de déterminer quelle propriété d'état est mise à jour; cela ressort déjà clairement de l'action expédiée.Voici un exemple à quoi cela peut ressembler:
la source
sendAmount
, etc. de manière asynchrone au lieu de les calculer, non? Cela change beaucoup. Il est possible de le faire avec,useReduce
mais cela peut être délicat. Si vous avez déjà traité avec Redux, vous savez peut-être que les opérations asynchrones ne sont pas simples. github.com/reduxjs/redux-thunk est une extension populaire pour Redux qui permet des actions asynchrones. Voici une démo qui augmente useReducer avec le même modèle (useThunkReducer), codesandbox.io/s/6z4r79ymwr . Notez que la fonction distribuée estasync
, vous pouvez y faire des requêtes (commentées).L'utilisation de Ref introduira un nouveau type de bogue dans l'application.
Voyons ce cas en utilisant ce
usePrevious
que quelqu'un a commenté auparavant:Comme nous pouvons le voir ici, nous ne mettons pas à jour l'interne
ref
car nous utilisonsuseEffect
la source
state
... et non leprops
... lorsque vous vous souciez des anciens accessoires, une erreur se produira.Pour une comparaison d'accessoires vraiment simple, vous pouvez utiliser useEffect pour vérifier facilement si un accessoire a été mis à jour.
useEffect n'exécutera alors votre code que si le prop change.
la source
prop
changements consécutifs , vous ne pourrez pas~ do stuff here ~
setHasPropChanged(false)
à la fin de~ do stuff here ~
pour "réinitialiser" votre état. (Mais cela réinitialiserait dans un rendu supplémentaire)En partant de la réponse acceptée, une solution alternative qui ne nécessite pas de hook personnalisé:
la source
useRef
nonuserRef
. J'ai oublié d'utiliser le courantprevAmount.current
Voici un crochet personnalisé que j'utilise et qui, à mon avis, est plus intuitif que de l'utiliser
usePrevious
.Vous utiliseriez
useTransition
comme suit.J'espère que cela pourra aider.
la source