Méthode de cycle de vie ReactJS à l'intérieur d'un composant de fonction

135

Au lieu d'écrire mes composants dans une classe, j'aimerais utiliser la syntaxe de la fonction à la place.

Comment remplacer componentDidMount, à l' componentWillMountintérieur des composants de fonction?
Est-ce même possible?

const grid = (props) => {
    console.log(props);
    let {skuRules} = props;

    const componentDidMount = () => {
        if(!props.fetched) {
            props.fetchRules();
        }
        console.log('mount it!');
    };
    return(
        <Content title="Promotions" breadcrumbs={breadcrumbs} fetched={skuRules.fetched}>
            <Box title="Sku Promotion">
                <ActionButtons buttons={actionButtons} />
                <SkuRuleGrid 
                    data={skuRules.payload}
                    fetch={props.fetchSkuRules}
                />
            </Box>      
        </Content>  
    )
}
Aftab Naveed
la source
1
les composants fonctionnels ne sont pas censés avoir des méthodes de cycle de vie. car ce ne sont que des fonctions. et les fonctions n'ont pas de méthodes. il y a des cours pour ça
avalanche1

Réponses:

149

Edit: Avec l'introduction de, Hooksil est possible d'implémenter un type de comportement de cycle de vie ainsi que l'état dans les composants fonctionnels. Actuellement

Les hooks sont une nouvelle proposition de fonctionnalité qui vous permet d'utiliser l'état et d'autres fonctionnalités React sans écrire de classe. Ils sont publiés dans React dans le cadre de la v16.8.0

useEffecthook peut être utilisé pour répliquer le comportement du cycle de vie et useStatepeut être utilisé pour stocker l'état dans un composant de fonction.

Syntaxe de base:

useEffect(callbackFunction, [dependentProps]) => cleanupFunction

Vous pouvez implémenter votre cas d'utilisation dans des crochets comme

const grid = (props) => {
    console.log(props);
    let {skuRules} = props;

    useEffect(() => {
        if(!props.fetched) {
            props.fetchRules();
        }
        console.log('mount it!');
    }, []); // passing an empty array as second argument triggers the callback in useEffect only after the initial render thus replicating `componentDidMount` lifecycle behaviour

    return(
        <Content title="Promotions" breadcrumbs={breadcrumbs} fetched={skuRules.fetched}>
            <Box title="Sku Promotion">
                <ActionButtons buttons={actionButtons} />
                <SkuRuleGrid 
                    data={skuRules.payload}
                    fetch={props.fetchSkuRules}
                />
            </Box>      
        </Content>  
    )
}

useEffectpeut également renvoyer une fonction qui sera exécutée lorsque le composant sera démonté. Cela peut être utilisé pour se désabonner des écouteurs, reproduisant le comportement de componentWillUnmount:

Par exemple: componentWillUnmount

useEffect(() => {
    window.addEventListener('unhandledRejection', handler);
    return () => {
       window.removeEventListener('unhandledRejection', handler);
    }
}, [])

Pour rendre useEffectconditionnel à des événements spécifiques, vous pouvez lui fournir un tableau de valeurs pour vérifier les modifications:

Par exemple: componentDidUpdate

componentDidUpdate(prevProps, prevState) {
     const { counter } = this.props;
     if (this.props.counter !== prevState.counter) {
      // some action here
     }
}

Crochets équivalents

useEffect(() => {
     // action here
}, [props.counter]); // checks for changes in the values in this array

Si vous incluez ce tableau, assurez-vous d'inclure toutes les valeurs de la portée du composant qui changent au fil du temps (accessoires, état), sinon vous risquez de finir par référencer les valeurs des rendus précédents.

Il y a quelques subtilités à utiliser useEffect; consultez l'API Here.


Avant la v16.7.0

La propriété des composants de fonction est qu'ils n'ont pas accès aux fonctions de cycle de vie Reacts ou au thismot - clé. Vous devez étendre la React.Componentclasse si vous souhaitez utiliser la fonction de cycle de vie.

class Grid extends React.Component  {
    constructor(props) {
       super(props)
    }

    componentDidMount () {
        if(!this.props.fetched) {
            this.props.fetchRules();
        }
        console.log('mount it!');
    }
    render() {
    return(
        <Content title="Promotions" breadcrumbs={breadcrumbs} fetched={skuRules.fetched}>
            <Box title="Sku Promotion">
                <ActionButtons buttons={actionButtons} />
                <SkuRuleGrid 
                    data={skuRules.payload}
                    fetch={props.fetchSkuRules}
                />
            </Box>      
        </Content>  
    )
  }
}

Les composants de fonction sont utiles lorsque vous souhaitez uniquement rendre votre composant sans avoir besoin de logique supplémentaire.

Shubham Khatri
la source
1
Comme je l'ai dit, vous avez une logique dans votre composant et votre exigence veut que vous utilisiez une fonction de cycle de vie et vous ne pouvez pas le faire avec des composants fonctionnels. Alors mieux vaut utiliser la classe. Utilisez un composant fonctionnel lorsque votre composant ne contient aucune logique supplémentaire
Shubham Khatri
1
Il convient de noter que ce n'est pas exactement l'équivalent de componentDidUpdate. useEffect(() => { // action here }, [props.counter])est déclenché lors du rendu initial, contrairement à componentDidUpdate.
Estus Flask
1
passing an empty array as second argument triggers the callback in useEffect only after the initial rendercela ressemble à une mauvaise façon de construire des trucs: / espérons que l'équipe de réaction proposera quelque chose de mieux dans les versions futures.
Lukas Liesis
3
alors? où est la partie où vous répondez comment exécuter du code sur componentwillmount?
Toskan le
59

Vous pouvez utiliser react-pure-lifecycle pour ajouter des fonctions de cycle de vie aux composants fonctionnels.

Exemple:

import React, { Component } from 'react';
import lifecycle from 'react-pure-lifecycle';

const methods = {
  componentDidMount(props) {
    console.log('I mounted! Here are my props: ', props);
  }
};

const Channels = props => (
<h1>Hello</h1>
)

export default lifecycle(methods)(Channels);
Yohann
la source
3
Qu'est-ce que c'est Grid? Je ne le vois défini nulle part dans votre extrait de code? Si vous vouliez également utiliser redux avec cela, pourriez-vous vous en tirer avec quelque chose comme export default lifecycle(methods)(connect({},{})(ComponentName))?
Sean Clancy
@SeanClancy Désolé pour la réponse tardive. L'extrait de code a été mis à jour.
Yohann
1
Est-ce considéré comme une bonne pratique? Dois-je essayer différentes solutions avant d'atteindre celle-ci ou est-ce que je peux l'utiliser si je le trouve plus simple?
SuperSimplePimpleDimple
9

Première solution: vous pouvez utiliser la nouvelle API react HOOKS. Actuellement dans React v16.8.0

Les hooks vous permettent d'utiliser plus de fonctionnalités de React sans classes. Les hooks fournissent une API plus directe aux concepts React que vous connaissez déjà: accessoires, état, contexte, références et cycle de vie . Hooks résout tous les problèmes résolus avec Recompose.

Une note de l'auteur de recompose(acdlite, 25 octobre 2018):

Salut! J'ai créé Recompose il y a environ trois ans. Environ un an après, j'ai rejoint l'équipe React. Aujourd'hui, nous avons annoncé une proposition pour Hooks. Hooks résout tous les problèmes que j'ai tenté de résoudre avec Recompose il y a trois ans, et plus encore. Je vais interrompre la maintenance active de ce paquet (à l'exclusion peut-être des corrections de bogues ou des correctifs pour la compatibilité avec les futures versions de React), et je recommanderai aux gens d'utiliser des Hooks à la place. Votre code existant avec Recompose fonctionnera toujours, ne vous attendez pas à de nouvelles fonctionnalités.

Solution deux:

Si vous utilisez la version react qui ne prend pas en charge les hooks, pas de soucis, utilisez recomposeplutôt (Une ceinture utilitaire React pour les composants fonctionnels et les composants d'ordre supérieur.). Vous pouvez utiliser recomposepour attacher lifecycle hooks, state, handlers etcà un composant de fonction.

Voici un composant sans rendu qui attache des méthodes de cycle de vie via le HOC de cycle de vie (à partir de recomposer).

// taken from https://gist.github.com/tsnieman/056af4bb9e87748c514d#file-auth-js-L33

function RenderlessComponent() {
  return null; 
}

export default lifecycle({

  componentDidMount() {
    const { checkIfAuthed } = this.props;
    // Do they have an active session? ("Remember me")
    checkIfAuthed();
  },

  componentWillReceiveProps(nextProps) {
    const {
      loadUser,
    } = this.props;

    // Various 'indicators'..
    const becameAuthed = (!(this.props.auth) && nextProps.auth);
    const isCurrentUser = (this.props.currentUser !== null);

    if (becameAuthed) {
      loadUser(nextProps.auth.uid);
    }

    const shouldSetCurrentUser = (!isCurrentUser && nextProps.auth);
    if (shouldSetCurrentUser) {
      const currentUser = nextProps.users[nextProps.auth.uid];
      if (currentUser) {
        this.props.setCurrentUser({
          'id': nextProps.auth.uid,
          ...currentUser,
        });
      }
    }
  }
})(RenderlessComponent);
Shivam
la source
4

Vous pouvez créer vos propres méthodes de cycle de vie.

Fonctions utilitaires

import { useEffect, useRef } from "react";

export const componentDidMount = handler => {
  return useEffect(() => {
    return handler();
  }, []);
};

export const componentDidUpdate = (handler, deps) => {
  const isInitialMount = useRef(true);

  useEffect(() => {
    if (isInitialMount.current) {
      isInitialMount.current = false;

      return;
    }

    return handler();
  }, deps);
};

Usage

import { componentDidMount, componentDidUpdate } from "./utils";

export const MyComponent = ({ myProp }) => {
  componentDidMount(() => {
    console.log("Component did mount!");
  });

  componentDidUpdate(() => {
    console.log("Component did update!");
  });

  componentDidUpdate(() => {
    console.log("myProp did update!");
  }, [myProp]);
};  
Etienne Martin
la source
2

Selon la documentation:

import React, { useState, useEffect } from 'react'
// Similar to componentDidMount and componentDidUpdate:

useEffect(() => {


});

voir la documentation React

DevB2F
la source
0

Si vous avez besoin d'utiliser React LifeCycle, vous devez utiliser Class.

Échantillon:

import React, { Component } from 'react';

class Grid extends Component {

 constructor(props){
  super(props)
 }

 componentDidMount () { /* do something */ }

 render () { 
   return <h1>Hello</h1>
 }

}
Gabriel Ferreira
la source
2
Je ne veux pas utiliser la classe.
Aftab Naveed le
3
La question était de savoir comment utiliser les méthodes de cycle de vie avec un composant fonctionnel, pas une classe.
Mike
Maintenant, avec React Hooks
Gabriel Ferreira
0

Vous pouvez utiliser le module create-react-class. Documentation officielle

Bien sûr, vous devez d'abord l'installer

npm install create-react-class

Voici un exemple de travail

import React from "react";
import ReactDOM from "react-dom"
let createReactClass = require('create-react-class')


let Clock = createReactClass({
    getInitialState:function(){
        return {date:new Date()}
    },

    render:function(){
        return (
            <h1>{this.state.date.toLocaleTimeString()}</h1>
        )
    },

    componentDidMount:function(){
        this.timerId = setInterval(()=>this.setState({date:new Date()}),1000)
    },

    componentWillUnmount:function(){
        clearInterval(this.timerId)
    }

})

ReactDOM.render(
    <Clock/>,
    document.getElementById('root')
)
Chandan Purohit
la source
0

si vous utilisez react 16.8, vous pouvez utiliser les hooks react ... Les hooks React sont des fonctions qui vous permettent de «vous connecter» à l'état React et aux fonctionnalités du cycle de vie des composants de fonction ... docs

WAEX
la source