Maison >interface Web >js tutoriel >Le problème avec les hooks orientés temps usePrevious et similaires
Theo a fait une vidéo cette semaine sur les comportements non intuitifs des hooks React, explorant notamment l'idée d'un hook appelé usePrevious, pour conserver la version valeur du dernier re-rendu, avant l'actuel. un. Une manière de faire un peu de logique avec l'ancien et le nouvel état.
Si vous voulez voir des idées sur la façon de l'implémenter, veuillez regarder la vidéo, dans cet article, l'idée est d'explorer l'aspect conceptuel d'avoir un hook comme usePrevious.
Comme vous pouvez le voir, nous n'avons pas de hook primitif comme celui-ci dans React. Avant les hooks, à l'ère basée sur les classes, nous avions une méthode de cycle de vie appelée composantDidUpdate où nous obtenions tous les états et accessoires précédents en tant que paramètres, pourquoi n'ont-ils pas conservé ce comportement avec les hooks ?
Cela peut être un peu répétitif si vous lisez cette série de posts, mais il faut parler du changement de paradigme, dans ce cas.
Avec les classes, lorsque certains états sont mis à jour, vous ne disposez pas de moyen automatique de recalculer les valeurs dérivées. Si vous utilisez des accessoires et des états spécifiques pour calculer une nouvelle valeur, vous devez vérifier par vous-même si certains d'entre eux ont changé.
De cette façon, la solution est d'avoir un rappel qui est appelé dans toutes les mises à jour, et d'envoyer à l'utilisateur les valeurs précédentes. Le code de l'application vérifie les différences et met à jour l'état calculé avec le nouveau résultat. Il s'agit de la simplicité des composants basés sur les classes, vous avez un contrôle total sur le flux de données et devez contrôler manuellement les calculs.
Nous arrivons ici aux expressions de réactivité.
Au lieu de devoir vérifier et faire le changement, vous écrivez une expression, la formule de calcul, en quelque sorte. Ce calcul doit être exécuté avec la version actuelle, sans accès à la précédente.
Imaginez une formule :
a = b + c b = 10 c = 20 a = 10 + 20 a = 30
Si j'utilise cette expression 1 million de fois, en passant b à 10 et c à 20, j'obtiendrai le même résultat. Ceci est un pur calcul. React exécute le même principe. Tous les calculs de dérivations doivent être purs.
Mais pourquoi est-ce important ?
Réagissez au travail dans les re-rendus. Chaque cycle génère une description de l'interface utilisateur et, en fonction des différences entre l'actuelle et la suivante, il valide les modifications dans le DOM. Chaque rendu est complètement séparé du précédent ou du suivant.
UI = fn(state)
Donc, pour chaque version d'état différente, nous avons une version d'interface utilisateur différente. Cela devient assez déroutant si nous ajoutons ici les valeurs précédentes. Car désormais, cela ne dépend plus seulement de l’État, mais aussi de l’État précédent. Au lieu d'avoir une source, une expression et un résultat, je peux avoir plusieurs sources, peut-être des expressions plus complexes pour gérer ces sources et une interface utilisateur incohérente et imprévisible en conséquence.
Chaque rendu se comportera différemment en fonction de l'état précédent. Et comme certaines des implémentations possibles de usePrevious reposent sur l'ordre temporel dans React, cela devient plus dangereux.
Avec des fonctionnalités concurrentes, React peut arrêter sans prévenir un rendu, pour prioriser d'autres actions. En fonction de useEffect et ref, vous pouvez conserver une version obsolète d'un rendu "précédent" qui est même le vrai précédent. Encore du désordre à raisonner.
Pensez avec une expression comme celle-ci
a = b + c b = 10 c = 20 a = 10 + 20 a = 30
Une partie de cela est prioritaire et doit être calculée au préalable, réfléchissons-y avec du code javascript :
UI = fn(state)
Nous avons donc maintenant deux expressions séparées qui peuvent être calculées séparément et qui sont parfaitement pures. Mais si la valeur de b change beaucoup et que le calcul de cdResult est coûteux, comment pouvons-nous le résoudre ? Mémoriser !
a = b + (c - d)
Maintenant, cdResult sera simplement recalculé si c ou d change.
Mais plus haut dans le texte j'ai dit qu'il n'y avait pas de valeur précédente, mais comment un calcul d'un rendu peut-il être utilisé dans le suivant ? Cela ne brise pas la pureté des calculs ?
En fait, non. Par exemple :
const cdResult = c - d; const a = b + cdResult;
Imaginez que nous sommes dans le rendu numéro 1. Le c a la valeur de 30 et d a la valeur de 20, donc le résultat est 10. Mais au fur et à mesure que je le mémorise, React gardera une trace des dépendances que j'ai ajoutées. le tableau. Si certains d'entre eux changent, il recalcule.
const cdResult = React.useMemo(() => c - d, [c, d]); const a = b + cdResult;
Mais ils n’ont pas changé. Si j'appelle à nouveau cette expression, avec c comme 30 et d comme 20, j'obtiendrai le même 10 comme résultat. Même si je suis dans le rendu numéro 2 et que d'autres variables ont changé, les dépendances que j'utilise dans ce calcul n'ont pas changé.
Je peux le recalculer à chaque rendu, c'est le comportement par défaut de React, mais je peux choisir de sauter un recalcul inutile qui renverra la même valeur, donc je l'ai gardé. On a gardé la pureté et on a gardé la séparation entre les rendus
Mais il existe un bon endroit pour faire de la logique avec l'état précédent et les actions de l'utilisateur. Bien sûr, au moment où le rappel est appelé, ce serait l'état actuel. Mais si vous avez un état qui doit changer en fonction d’une certaine logique, c’est l’endroit idéal.
Bien sûr, il peut y avoir des cas très spécifiques où vous aurez peut-être besoin d'un hook tel que usePrevious, mais soyez conscient des incohérences que cela peut provoquer, et essayez d'ajouter des garanties pour éviter les bugs sur l'application.
Et surtout, si possible, évitez-le.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!