436 votes

Comment utiliser componentWillMount() dans les React Hooks?

Dans la documentation officielle de React, il est mentionné -

Si vous êtes familier avec les méthodes de cycle de vie des classes React, vous pouvez penser au Hook useEffect comme combinant componentDidMount, componentDidUpdate et componentWillUnmount.

Ma question est - comment pouvons-nous utiliser la méthode de cycle de vie componentWillMount() dans un hook?

752voto

Vous ne pouvez pas utiliser les méthodes de cycle de vie existantes (componentDidMount, componentDidUpdate, componentWillUnmount, etc.) dans un hook. Elles ne peuvent être utilisées que dans les composants de classe. Et avec les Hooks, vous ne pouvez les utiliser que dans les composants fonctionnels. La ligne ci-dessous provient de la documentation de React :

Si vous êtes familier avec les méthodes de cycle de vie de classe React, vous pouvez considérer le Hook useEffect comme combinant componentDidMount, componentDidUpdate et componentWillUnmount.

La suggestion est que vous pouvez imiter ces méthodes de cycle de vie des composants de classe dans des composants fonctionnels.

Le code à l'intérieur de componentDidMount s'exécute une fois lorsque le composant est monté. L'équivalent du hook useEffect pour ce comportement est

useEffect(() => {
  // Votre code ici
}, []);

Notez le deuxième paramètre ici (un tableau vide). Cela ne s'exécutera qu'une seule fois.

Sans le deuxième paramètre, le hook useEffect sera appelé à chaque rendu du composant, ce qui peut être dangereux.

useEffect(() => {
  // Votre code ici
});

componentWillUnmount est utilisé pour le nettoyage (comme la suppression des écouteurs d'événement, l'annulation du minuteur, etc.). Disons que vous ajoutez un écouteur d'événement dans componentDidMount et le supprimez dans componentWillUnmount comme ci-dessous.

componentDidMount() {
  window.addEventListener('mousemove', () => {})
}

componentWillUnmount() {
  window.removeEventListener('mousemove', () => {})
}

L'équivalent en Hook du code ci-dessus sera le suivant

useEffect(() => {
  window.addEventListener('mousemove', () => {});

  // la fonction retournée sera appelée lors du démontage du composant
  return () => {
    window.removeEventListener('mousemove', () => {})
  }
}, [])

425 votes

Bonne explication pour les autres événements du cycle de vie, mais cela ne répond pas spécifiquement à la question sur une alternative à componentWillMount().

3 votes

Dans les exemples de PanResponder que j'ai vus, componentWillMount semble être nécessaire, sinon vous obtenez des panHandlers indéfinis.

1 votes

Veuillez noter le [] comme le deuxième argument de useEffect. Sans lui, l'effet est exécuté à chaque rendu, et pas seulement lors du premier rendu. Comme [] est le même à chaque fois, React pense que l'effet a déjà été appliqué (comprendre : la programmation dynamique/mémoïsation est en jeu), et ne réexécute pas votre fonction.

254voto

Ben Carp Points 1515

utiliser le hook useComponentWillMount

const useComponentWillMount = (cb) => {
    const willMount = useRef(true)

    if (willMount.current) cb()

    willMount.current = false
}

Ce hook pourrait être utile lorsqu'il y a un problème de séquence (comme s'exécuter avant un autre script). Si ce n'est pas le cas, utilisez plutôt useComponentDidMount qui est plus conforme au paradigme des hooks React.

utiliser le hook useComponentDidMount

const useComponentDidMount = cb => useEffect(cb, []);

Si vous savez que votre effet ne doit s'exécuter qu'une seule fois au début, utilisez cette solution. Il s'exécutera une seule fois après le montage du composant.

paradigme useEffect

Les composants de classe ont des méthodes de cycle de vie qui sont définies comme des points dans la chronologie du composant. Les hooks ne suivent pas ce paradigme. Au lieu de cela, les effets devraient être structurés selon leur contenu.

function Post({postID}){
  const [post, setPost] = useState({})

  useEffect(()=>{
    fetchPosts(postID).then(
      (postObject) => setPost(postObject)
    )
  }, [postID])

  ...
}

Dans l'exemple ci-dessus, l'effet traite de la récupération du contenu d'un article. Au lieu d'un certain moment dans le temps, il a une valeur dont il dépend - postID. Chaque fois que postID obtient une nouvelle valeur (y compris lors de l'initialisation), il se réexécutera.

Discussion sur Component Will Mount

Dans les composants de classe, componentWillMount est considéré comme obsolète (source 1, source 2). Il est obsolète car il pourrait s'exécuter plus d'une fois, et il existe une alternative - utiliser le constructeur. Ces considérations ne sont pas pertinentes pour un composant fonctionnel.

67 votes

C'est la seule réponse qui répond à la question et a du sens. Merci !

4 votes

Le seul problème avec cela est que vous obtenez un rendu supplémentaire en raison de la mise à jour de l'état impliquée. En utilisant une ref à la place, vous obtenez le comportement désiré sans le rendu supplémentaire : ` const useComponentWillMount = func => { const willMount = useRef(true); useEffect(() => { willMount.current = false; }, []); if (willMount.current) { func(); } }; `

4 votes

Cette implémentation fonctionnelle de componentWillMount basée sur useEffect présente deux problèmes. Le premier est qu'il n'y a pas de cycle de montage dans les composants fonctionnels, les deux hooks s'exécuteront après que le composant ait été rendu, donc Runs only once before component mounts est trompeur. Le deuxième est que componentWillMount est appelé lors du rendu côté serveur et useEffect non. De nombreuses bibliothèques s'appuient toujours sur UNSAFE_componentWillMount car c'est actuellement le seul moyen de déclencher un effet secondaire côté serveur.

77voto

MING WU Points 2121

According to reactjs.org, componentWillMount will not be supported in the future. https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

Il n'est plus nécessaire d'utiliser componentWillMount.

Si vous souhaitez faire quelque chose avant que le composant ne soit monté, faites-le simplement dans le constructeur().

Si vous voulez effectuer des requêtes réseau, ne le faites pas dans componentWillMount. Cela pourrait entraîner des bugs inattendus.

Les requêtes réseau peuvent être effectuées dans componentDidMount.

J'espère que cela vous aidera.


mis à jour le 08/03/2019

La raison pour laquelle vous demandez componentWillMount est probablement parce que vous souhaitez initialiser l'état avant le rendu.

Faites-le simplement dans useState.

const helloWorld=()=>{
    const [value,setValue]=useState(0) //initialisez votre état ici
    return {value}
}
export default helloWorld;

Ou peut-être que vous souhaitez exécuter une fonction dans componentWillMount, par exemple, si votre code original ressemble à ceci :

componentWillMount(){
  console.log('componentWillMount')
}

Avec les hooks, tout ce que vous avez à faire est de supprimer la méthode de cycle de vie :

const hookComponent=()=>{
    console.log('componentWillMount')
    return you have transfered componeWillMount from class component into hook 
}

Je souhaite ajouter quelque chose à la première réponse concernant useEffect.

useEffect(()=>{})

useEffect s'exécute à chaque rendu, c'est une combinaison de componentDidUpdate, componentDidMount et componentWillUnmount.

 useEffect(()=>{},[])

Si nous ajoutons un tableau vide dans useEffect, cela s'exécute juste lorsque le composant est monté. C'est parce que useEffect comparera le tableau que vous lui aurez passé. Ainsi, il n'est pas nécessaire que ce soit un tableau vide. Il peut s'agir d'un tableau qui ne change pas. Par exemple, cela peut être [1,2,3] ou ['1,2']. useEffect s'exécute toujours uniquement lorsque le composant est monté.

À vous de décider si vous voulez qu'il s'exécute une seule fois ou à chaque rendu. Ce n'est pas dangereux si vous oubliez d'ajouter un tableau tant que vous savez ce que vous faites.

J'ai créé un exemple d'utilisation des hooks. Veuillez le consulter.

https://codesandbox.io/s/kw6xj153wr


mis à jour le 21/08/2019

Cela fait un moment que j'ai écrit la réponse ci-dessus. Il y a quelque chose sur lequel je pense que vous devriez prêter attention. Lorsque vous utilisez

useEffect(()=>{},[])

Lorsque react compare les valeurs que vous avez passées au tableau [], il utilise Object.is() pour comparer. Si vous lui passez un objet, comme

useEffect(()=>{},[{name:'Tom'}])

C'est exactement la même chose que :

useEffect(()=>{})

Cela se rechargera à chaque fois parce que lorsque Object.is() compare un objet, il compare sa référence, pas la valeur elle-même. C'est la même raison pour laquelle {}==={} retourne false car leurs références sont différentes. Si vous souhaitez toujours comparer l'objet lui-même et non la référence, vous pouvez faire quelque chose comme ceci :

useEffect(()=>{},[JSON.stringify({name:'Tom'})])

Mise à jour du 7/09/2021 :

Quelques mises à jour concernant la dépendance :

En règle générale, si vous utilisez une fonction ou un objet comme dépendance, le composant se réexécutera toujours. Mais react vous fournit déjà la solution : useCallback et useMemo

useCallback permet de mémoriser une fonction. useMemo permet de mémoriser un objet.

Consultez cet article :

https://javascript.plainenglish.io/5-useeffect-infinite-loop-patterns-2dc9d45a253f

32 votes

Et la question était comment le mettre en œuvre avec des hooks

5 votes

Mais tu n'as pas besoin de l'implémenter avec des hooks car ce ne sera pas pris en charge. Pas besoin d'apprendre comment faire cela avec des hooks.

1 votes

Maintenant que vous avez mentionné que componentDidMount est le cycle de vie correct à utiliser, vous auriez pu ajouter comment implémenter cela dans votre réponse, et alors votre réponse aurait plus de sens que la réponse acceptée.

35voto

lokender singh Points 311

Méthodes du cycle de vie de React dans les hooks

pour une référence visuelle simple, suivez cette image

entrer la description de l'image ici

Comme vous pouvez le voir simplement dans l'image ci-dessus, pour ComponentWillUnmount, vous devez faire comme ceci

 useEffect(() => {
    return () => {
        console.log('componentWillUnmount');
    };
   }, []);

1 votes

Merci ! Pourriez-vous mettre ici un lien vers l'article / la publication d'origine ? La qualité de l'image est mauvaise [ ].

7 votes

La question concerne componentWillMount, pas componentWillUnmount

27voto

jpmarks Points 808

Vous pouvez pirater le crochet useMemo pour imiter un événement de cycle de vie componentWillMount. Il suffit de faire :

const Component = () => {
   useMemo(() => {
     // événements componentWillMount
   },[]);
   useEffect(() => {
     // événements componentDidMount
     return () => {
       // événements componentWillUnmount
     }
   }, []);
};

Vous devriez garder le crochet useMemo avant tout ce qui interagit avec votre état. Ce n'est pas son but initial, mais cela a fonctionné pour moi pour tous les problèmes de componentWillMount.

Cela fonctionne car useMemo ne nécessite pas réellement de retourner une valeur et vous n'avez pas réellement à l'utiliser comme quoi que ce soit, mais comme il mémorise une valeur en fonction des dépendances qui ne seront exécutées qu'une seule fois ("[]") et qu'il est en haut de notre composant, il s'exécute une fois lorsque le composant est monté avant tout le reste.

0 votes

Brillant! Merci!

6 votes

Cela peut fonctionner avec l'implémentation actuelle, mais la documentation de React dit spécifiquement de ne pas le faire. Vous pouvez compter sur useMemo comme une optimisation de performance, et non comme une garantie sémantique. reactjs.org/docs/hooks-reference.html#usememo

0 votes

Je suis d'accord. C'est légèrement risqué, mais si vous l'utilisez avec précaution, vous pouvez obtenir ce que vous cherchez. Je le trouve utile pour initialiser des choses qui sont indépendantes de l'état de rendu des composants.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X