Método de ciclo de vida ReactJS dentro de um componente de função

134

Em vez de escrever meus componentes dentro de uma classe, gostaria de usar a sintaxe da função.

Como faço para substituir componentDidMount, componentWillMountdentro dos componentes da função?
É mesmo possível?

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
fonte
1
os componentes funcionais não devem ter métodos de ciclo de vida. porque são apenas funções. e as funções não têm métodos. há aulas para isso
avalanche1

Respostas:

148

Edit: Com a introdução do Hooks, é possível implementar um tipo de comportamento de ciclo de vida, bem como o estado nos componentes funcionais. Atualmente

Os ganchos são uma nova proposta de recurso que permite usar o estado e outros recursos do React sem escrever uma classe. Eles foram lançados no React como parte da v16.8.0

useEffectO gancho pode ser usado para replicar o comportamento do ciclo de vida e useStatepode ser usado para armazenar o estado em um componente de função.

Sintaxe básica:

useEffect(callbackFunction, [dependentProps]) => cleanupFunction

Você pode implementar seu caso de uso em 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>  
    )
}

useEffecttambém pode retornar uma função que será executada quando o componente for desmontado. Isso pode ser usado para cancelar a assinatura de ouvintes, replicando o comportamento de componentWillUnmount:

Ex .: componentWillUnmount

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

Para tornar useEffectcondicional a eventos específicos, você pode fornecer uma matriz de valores para verificar as alterações:

Ex: componentDidUpdate

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

Equivalente a ganchos

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

Se você incluir esta matriz, certifique-se de incluir todos os valores do escopo do componente que mudam com o tempo (props, estado), ou você pode acabar fazendo referência a valores de renderizações anteriores.

Existem algumas sutilezas para usar useEffect; verifique a API Here.


Antes da v16.7.0

A propriedade dos componentes de função é que eles não têm acesso às funções do ciclo de vida do Reacts ou à thispalavra - chave. Você precisa estender a React.Componentclasse se quiser usar a função 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>  
    )
  }
}

Os componentes de função são úteis quando você deseja apenas renderizar seu componente sem a necessidade de lógica extra.

Shubham Khatri
fonte
1
Como eu disse, você tem uma lógica em seu componente e seu requisito quer que você use uma função de ciclo de vida e você não pode fazer isso com componentes funcionais. Portanto, é melhor aproveitar a aula. Use o componente funcional quando seu componente não contiver lógica extra
Shubham Khatri
1
Deve-se notar que este não é o equivalente exato de componentDidUpdate. useEffect(() => { // action here }, [props.counter])é disparado na renderização inicial, enquanto o componentDidUpdate não.
Estus Flask
1
passing an empty array as second argument triggers the callback in useEffect only after the initial renderisso soa como uma maneira hacky suja de construir coisas: / espero que a equipe react venha com algo melhor em lançamentos futuros.
Lukas Liesis
3
tão? onde está a parte em que você responde como executar o código em componentwillmount?
Toskan
59

Você pode usar o react-pure-lifecycle para adicionar funções de ciclo de vida a componentes funcionais.

Exemplo:

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
fonte
3
O que é Grid? Não o vejo definido em nenhum lugar do seu snippet de código? Se você também quisesse usar redux com isso, poderia usar algo como export default lifecycle(methods)(connect({},{})(ComponentName))?
Sean Clancy
@SeanClancy Desculpe pela resposta tardia. O snippet de código foi atualizado.
Yohann de
1
Isso é considerado uma boa prática? Devo tentar soluções diferentes antes de chegar a esta ou posso usá-la se eu achar mais fácil?
SuperSimplePimpleDimple
9

Solução um: você pode usar a nova API react HOOKS . Atualmente no React v16.8.0

Os ganchos permitem que você use mais recursos do React sem classes. Os ganchos fornecem uma API mais direta para os conceitos do React que você já conhece: props, state, context, refs e lifecycle . Hooks resolve todos os problemas tratados com Recompose.

Uma nota do autor de recompose(acdlite, 25 de outubro de 2018):

Oi! Criei o Recompose há cerca de três anos. Cerca de um ano depois disso, entrei para a equipe React. Hoje, anunciamos uma proposta para Hooks. Hooks resolve todos os problemas que tentei resolver com Recompose três anos atrás, e mais ainda. Estarei descontinuando a manutenção ativa deste pacote (excluindo talvez correções de bugs ou patches para compatibilidade com versões futuras do React) e recomendarei que as pessoas usem os Hooks. Seu código existente com Recompose ainda funcionará, mas não espere novos recursos.

Solução dois:

Se você estiver usando a versão do react que não suporta ganchos, não se preocupe, use recompose(Um cinto de utilidades do React para componentes de função e componentes de ordem superior). Você pode usar recomposepara anexarlifecycle hooks, state, handlers etc a um componente de função.

Aqui está um componente sem renderização que anexa métodos de ciclo de vida por meio do ciclo de vida HOC (da recomposição).

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

Você pode fazer seus próprios métodos de ciclo de vida.

Funções utilitárias

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 Martin
fonte
2

De acordo com a documentação:

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

useEffect(() => {


});

consulte a documentação do React

DevB2F
fonte
0

Se você precisar usar o React LifeCycle, precisará usar Class.

Amostra:

import React, { Component } from 'react';

class Grid extends Component {

 constructor(props){
  super(props)
 }

 componentDidMount () { /* do something */ }

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

}
Gabriel ferreira
fonte
2
Eu não quero usar a classe.
Aftab Naveed
3
A questão era como usar métodos de ciclo de vida com um componente funcional, não uma classe.
Mike,
Agora, com React Hooks
Gabriel Ferreira
0

Você pode usar o módulo criar-reagir-classe. Documentação oficial

Claro, você deve primeiro instalá-lo

npm install create-react-class

Aqui está um exemplo prático

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

se estiver usando o react 16.8, você pode usar os Ganchos react ... Os Ganchos React são funções que permitem que você “enganche” o estado do React e os recursos de ciclo de vida dos componentes da função ... docs

WAEX
fonte