Metodo del ciclo di vita di ReactJS all'interno di una funzione Component


135

Invece di scrivere i miei componenti all'interno di una classe, vorrei utilizzare invece la sintassi della funzione.

Come faccio a ignorare componentDidMount, componentWillMountdentro componenti di funzione?
È anche possibile?

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>  
    )
}

1
i componenti funzionali non dovrebbero avere metodi del ciclo di vita. perché sono solo funzioni. e le funzioni non hanno metodi. ci sono classi per questo
valanga1

Risposte:


149

Modifica: con l'introduzione di Hooksè possibile implementare un tipo di comportamento del ciclo di vita così come lo stato nei componenti funzionali. Attualmente

Gli hook sono una nuova proposta di funzionalità che ti consente di utilizzare state e altre funzionalità di React senza scrivere una classe. Sono rilasciati in React come parte della v16.8.0

useEffect hook può essere utilizzato per replicare il comportamento del ciclo di vita e useState può essere utilizzato per memorizzare lo stato in un componente funzione.

Sintassi di base:

useEffect(callbackFunction, [dependentProps]) => cleanupFunction

Puoi implementare il tuo caso d'uso in hook come

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>  
    )
}

useEffectpuò anche restituire una funzione che verrà eseguita quando il componente viene smontato. Questo può essere utilizzato per annullare l'iscrizione agli ascoltatori, replicando il comportamento dicomponentWillUnmount :

Ad esempio: componentWillUnmount

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

Per rendere useEffectcondizionale a eventi specifici, puoi fornire un array di valori per verificare le modifiche:

Ad esempio: componentDidUpdate

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

Equivalente di ganci

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

Se includi questo array, assicurati di includere tutti i valori dell'ambito del componente che cambiano nel tempo (props, state), altrimenti potresti finire per fare riferimento a valori di rendering precedenti.

Ci sono alcune sottigliezze nell'utilizzo useEffect; controlla l'API Here.


Prima della v16.7.0

La proprietà dei componenti funzione è che non hanno accesso alle funzioni del ciclo di vita di Reacts o alla thisparola chiave. È necessario estendere la React.Componentclasse se si desidera utilizzare la funzione del ciclo di vita.

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>  
    )
  }
}

I componenti funzione sono utili quando si desidera eseguire il rendering del componente senza la necessità di logica aggiuntiva.


1
Come ho detto, hai una logica nel tuo componente e il tuo requisito vuole che tu usi una funzione del ciclo di vita e non puoi farlo con i componenti functioanl. Quindi è meglio usare la classe. Usa componente funzionale quando il tuo componente non contiene logica aggiuntiva
Shubham Khatri

1
Va notato che questo non è l'equivalente esatto di componentDidUpdate. useEffect(() => { // action here }, [props.counter])viene attivato al rendering iniziale mentre componentDidUpdate no.
Estus Flask

1
passing an empty array as second argument triggers the callback in useEffect only after the initial renderquesto suona come un modo sporco e hacky per costruire roba: / si spera che il team di reazione troverà qualcosa di meglio nelle versioni future.
Lukas Liesis

3
così? dov'è la parte in cui rispondi a come eseguire il codice su componentwillmount?
Toskan

59

È possibile utilizzare react-pure-lifecycle per aggiungere funzioni del ciclo di vita ai componenti funzionali.

Esempio:

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);

3
Che cos'è Grid? Non lo vedo definito da nessuna parte nello snippet di codice? Se volessi usare redux anche con questo potresti farla franca con qualcosa del genere export default lifecycle(methods)(connect({},{})(ComponentName))?
Sean Clancy

@SeanClancy Ci scusiamo per la risposta in ritardo. Lo snippet di codice è stato aggiornato.
Yohann

1
È considerata una buona pratica? Devo provare diverse soluzioni prima di arrivare a questa o va bene usarla se la trovo più semplice?
SuperSimplePimpleDimple

9

Soluzione uno: puoi utilizzare la nuova API React HOOKS . Attualmente in React v16.8.0

Gli hook ti consentono di utilizzare più funzionalità di React senza classi. Gli hook forniscono un'API più diretta ai concetti di React che già conosci: props, state, context, refs e lifecycle . Hooks risolve tutti i problemi risolti con Recompose.

Una nota dell'autore di recompose (acdlite, 25 ottobre 2018):

Ciao! Ho creato Recompose circa tre anni fa. Circa un anno dopo, sono entrato a far parte del team React. Oggi abbiamo annunciato una proposta per Hooks. Hooks risolve tutti i problemi che ho tentato di affrontare con Recompose tre anni fa, e altri ancora. Interromperò la manutenzione attiva di questo pacchetto (escludendo forse correzioni di bug o patch per compatibilità con i futuri rilasci di React) e raccomanderò che le persone usino invece gli Hooks. Il tuo codice esistente con Recompose continuerà a funzionare, ma non aspettarti nuove funzionalità.

Soluzione due:

Se stai usando la versione recomposeReact che non supporta i hook, non preoccuparti, usa invece (A React utility belt per componenti funzionali e componenti di ordine superiore.). Puoi usare recomposeper allegarelifecycle hooks, state, handlers etc a un componente di funzione.

Ecco un componente senza rendering che collega i metodi del ciclo di vita tramite l'HOC del ciclo di vita (da ricomporre).

// 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);

4

Puoi creare i tuoi metodi del ciclo di vita.

Funzioni di utilità

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);
};

uso

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]);
};  

2

Secondo la documentazione:

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

useEffect(() => {


});

vedere la documentazione di React


0

Se hai bisogno di usare React LifeCycle, devi usare Class.

Campione:

import React, { Component } from 'react';

class Grid extends Component {

 constructor(props){
  super(props)
 }

 componentDidMount () { /* do something */ }

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

}

2
Non voglio usare la classe.
Aftab Naveed il

3
La domanda era come utilizzare i metodi del ciclo di vita con un componente funzionale, non una classe.
Mike

Ora, con React Hooks
Gabriel Ferreira,

0

Puoi utilizzare il modulo create-react-class. Documentazione ufficiale

Ovviamente devi prima installarlo

npm install create-react-class

Ecco un esempio funzionante

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')
)

0

se stai usando React 16.8 puoi usare React Hooks ... React Hooks sono funzioni che ti permettono di "agganciarti" allo stato di React e alle caratteristiche del ciclo di vita dai componenti della funzione ... docs

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.