Nous avons migré vers 'React Functional Components' au lieu de 'Class based Component'. Je ne trouve pas la logique de remplacement pour la Dans les composants basés sur la setState
fonction de rappel a >. C'est-à-dire que j'ai un composant fonctionnel avec état, et je souhaite créer une fonction de gestionnaire d'événements qui mute l'état plusieurs fois dans l'ordre, la mise en garde étant que je ne connais pas la valeur actuelle de l'état (cela peut être true code> /
false
). L'exemple suivant peut avoir plus de sens: const Example = () => {
const [ openDoor, setOpenDoor ] = useState(false);
// the following handler should swich 'openDoor' state to inverse of
// current state value. Then after setTimeout duration, inverse it again
const toggleOpenDoor = () => {
setOpenDoor(!openDoor);
// within setTimeout below, '!openDoor' does not work because it still
// receives the same value as above because of async nature of
// state updates
setTimeout(() => setOpenDoor(!openDoor), 500)
}
return(...);
}
classe
, nous avions un argument de rappel qui mettrait à jour l'état après la mise à jour précédente. Comment obtenir la même chose dans le composant fonctionnel ci-dessus en utilisant le hook d'état?
6 Réponses :
Vous pouvez utiliser le hook useEffect pour voir quand le changement d'état s'est produit.
useEffect(() => { // do something console.log('openDoor change', openDoor) }, [openDoor]);
Vous devez expliquer comment utiliser le délai d'expiration dans useEffect
comme OP le demande.
Je vais vous dire que cela fonctionne à peu près de la même manière que this.setState
, vous passez simplement une fonction de rappel qui prend l'état précédent comme paramètre et renvoie un nouvel état href = "https://reactjs.org/docs/hooks-reference.html#functional-updates" rel = "nofollow noreferrer"> docs )
const Example = () => { const [openDoor, setOpenDoor] = useState(false); useEffect(() => { console.log('openDoor changed!', openDoor) }, [openDoor]) const toggleOpenDoor = () => { setOpenDoor(!openDoor); setTimeout(() => setOpenDoor(prevDoor => !prevDoor), 500) } return(...); }
Pour vous savez quand cela change, vous pouvez utiliser le callback useEffect
, qui sera appelé chaque fois que quelque chose change dans le tableau des dépendances ( docs )
const Example = () => { const [openDoor, setOpenDoor] = useState(false); const toggleOpenDoor = () => { setOpenDoor(!openDoor); setTimeout(() => setOpenDoor(prevDoor => !prevDoor), 500) } return(...); }
:)
Vous pouvez utiliser le hook useEffect
pour y parvenir.
setOpenDoor(!openDoor); useEffect(() => { // Here your next setState function }, [openDoor]);
Pour plus d'informations sur les hooks, veuillez consulter https://reactjs.org/docs/hooks-effect.html
Vous devez simplement utiliser setTimeout
dans le rappel useEffect
:
const App = () => { const [openDoor, setOpenDoor] = useState(false); const toggle = () => setOpenDoor(prevOpen => !prevOpen); useEffect(() => { const id = setTimeout(() => toggle(), 1000); return () => clearTimeout(id); }, [openDoor]); return <Container>isOpen: {String(openDoor)}</Container>; };
import React, { useState, useEffect } from "react"; const Example = () => { const [openDoor, setOpenDoor] = useState(false); const toggleOpenDoor = () => { setOpenDoor(!openDoor); }; useEffect(() => { console.log(openDoor); if (openDoor) { setTimeout(() => setOpenDoor(!openDoor), 1500); } }, [openDoor]); return ( <> <button onClick={toggleOpenDoor}>Toggle</button> <p>{`openDoor: ${openDoor}`}</p> </> ); }; export default Example; Codesandbox
Je me demande si useEffect est la meilleure solution. Surtout lorsque l'appel de setTimeout dans useEffect va provoquer une boucle infinie puisque chaque fois que nous appelons setOpenDoor, l'application rend puis useEffect est appelée à nouveau en appelant une fonction setOpenDoor ... Graphiquement:
const toggleOpenDoor = () => { setOpenDoor(!openDoor); setTimeout(() => setOpenDoor(openDoor => !openDoor), 500); };
Je pense que vous pouvez faire quelque chose comme
setOpenDoor (prevOpenDoor =>! PrevOpenDoor)