Método del ciclo de vida de ReactJS dentro de un componente de función

135

En lugar de escribir mis componentes dentro de una clase, me gustaría usar la sintaxis de la función.

¿Cómo puedo reemplazar componentDidMount, componentWillMountdentro de los componentes de la función?
¿Es siquiera posible?

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
fuente
1
Se supone que los componentes funcionales no tienen métodos de ciclo de vida. porque son solo funciones. y las funciones no tienen métodos. hay clases para eso
avalanche1

Respuestas:

149

Editar: Con la introducción de Hookses posible implementar un tipo de comportamiento del ciclo de vida, así como el estado en los Componentes funcionales. Actualmente

Los Hooks son una nueva propuesta de funciones que te permite usar el estado y otras funciones de React sin escribir una clase. Se lanzan en React como parte de v16.8.0

useEffectEl gancho se puede usar para replicar el comportamiento del ciclo de vida y useStatese puede usar para almacenar el estado en un componente de función.

Sintaxis básica:

useEffect(callbackFunction, [dependentProps]) => cleanupFunction

Puede implementar su caso de uso en ganchos como

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

useEffecttambién puede devolver una función que se ejecutará cuando se desmonte el componente. Esto se puede usar para cancelar la suscripción a los oyentes, replicando el comportamiento de componentWillUnmount:

Por ejemplo: componentWillUnmount

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

Para useEffectcondicionar eventos específicos, puede proporcionarle una matriz de valores para verificar cambios:

Por ejemplo: componentDidUpdate

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

Equivalente de ganchos

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

Si incluye esta matriz, asegúrese de incluir todos los valores del alcance del componente que cambian con el tiempo (accesorios, estado), o puede terminar haciendo referencia a valores de representaciones anteriores.

Hay algunas sutilezas en el uso useEffect; echa un vistazo a la API Here.


Antes de v16.7.0

La propiedad de los componentes de función es que no tienen acceso a las funciones del ciclo de vida de Reacts ni a la thispalabra clave. Necesita extender la React.Componentclase si desea utilizar la función de ciclo de vida.

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

Los componentes de función son útiles cuando solo desea renderizar su componente sin la necesidad de lógica adicional.

Shubham Khatri
fuente
1
Como dije, tiene una lógica en su componente y su requisito quiere que use una función de ciclo de vida y no puede hacerlo con componentes funcionales. Así que mejor haga uso de la clase. Use el componente funcional cuando su componente no contenga lógica adicional
Shubham Khatri
1
Debe tenerse en cuenta que esto no es exactamente equivalente a componentDidUpdate. useEffect(() => { // action here }, [props.counter])se activa en el procesamiento inicial, mientras que componentDidUpdate no lo hace.
Estus Flask
1
passing an empty array as second argument triggers the callback in useEffect only after the initial renderesto suena como una forma sucia y hacky de construir cosas: / con suerte, el equipo de reacción encontrará algo mejor en futuras versiones.
Lukas Liesis
3
¿entonces? ¿Dónde está la parte en la que responde cómo ejecutar código en componentwillmount?
Toskan
59

Puede usar react-pure-lifecycle para agregar funciones de ciclo de vida a componentes funcionales.

Ejemplo:

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
fuente
3
¿Qué es Grid? ¿No lo veo definido en ninguna parte de su fragmento de código? Si quisieras usar redux con esto también, ¿podrías salirte con la tuya con algo como export default lifecycle(methods)(connect({},{})(ComponentName))?
Sean Clancy
@SeanClancy Lo siento por la respuesta tardía. Se actualizó el fragmento de código.
Yohann
1
¿Se considera esto una buena práctica? ¿Debo probar diferentes soluciones antes de buscar esta o está bien usarla si me resulta más fácil?
SuperSimplePimpleDimple
9

Solución 1: puede utilizar la nueva API react HOOKS . Actualmente en React v16.8.0

Los Hooks te permiten usar más funciones de React sin clases. Los Hooks proporcionan una API más directa a los conceptos de React que ya conoce: props, state, context, refs y lifecycle . Hooks resuelve todos los problemas que se abordan con Recompose.

Una nota del autor de recompose(acdlite, 25 de octubre de 2018):

¡Hola! Creé Recompose hace unos tres años. Aproximadamente un año después de eso, me uní al equipo de React. Hoy, anunciamos una propuesta para Hooks. Hooks resuelve todos los problemas que intenté abordar con Recompose hace tres años, y más. Descontinuaré el mantenimiento activo de este paquete (excluyendo quizás correcciones de errores o parches para compatibilidad con futuras versiones de React), y recomendaré que la gente use Hooks en su lugar. Su código existente con Recompose seguirá funcionando, pero no espere nuevas funciones.

Solución dos:

Si está utilizando la versión de recomposeReact que no admite hooks, no se preocupe, use (A React utility belt para componentes de función y componentes de orden superior) en su lugar. Puede utilizar recomposepara adjuntar lifecycle hooks, state, handlers etca un componente de función.

Aquí hay un componente sin renderizado que adjunta métodos de ciclo de vida a través del ciclo de vida HOC (de recomposición).

// 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
fuente
4

Puede crear sus propios métodos de ciclo de vida.

Funciones de utilidad

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]);
};  
Etienne Martín
fuente
2

Según la documentación:

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

useEffect(() => {


});

ver la documentación de React

DevB2F
fuente
0

Si necesita usar React LifeCycle, necesita usar Class.

Muestra:

import React, { Component } from 'react';

class Grid extends Component {

 constructor(props){
  super(props)
 }

 componentDidMount () { /* do something */ }

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

}
Gabriel Ferreira
fuente
2
No quiero usar la clase.
Aftab Naveed
3
La pregunta era cómo usar métodos de ciclo de vida con un componente funcional, no con una clase.
Mike
Ahora, con React Hooks
Gabriel Ferreira
0

Puede hacer uso del módulo create-react-class. Documentación oficial

Por supuesto que primero debes instalarlo

npm install create-react-class

Aquí hay un ejemplo de trabajo

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
fuente
0

si usa react 16.8, puede usar react Hooks ... React Hooks son funciones que le permiten "conectarse" al estado de React y las características del ciclo de vida de los componentes de funciones ... docs

WAEX
fuente