Метод жизненного цикла ReactJS внутри компонента функции

136

Вместо того, чтобы писать свои компоненты внутри класса, я хотел бы использовать синтаксис функции.

Как переопределить componentDidMount, componentWillMountвнутри компонентов функции?
Это вообще возможно?

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
функциональные компоненты не должны иметь методов жизненного цикла. потому что это просто функции. а у функций нет методов. для этого есть классы
avalanche1

Ответы:

153

Изменить: с введениемHooks можно реализовать поведение жизненного цикла, а также состояние в функциональных компонентах. В настоящее время

Хуки - это новая функция, которая позволяет вам использовать состояние и другие функции React без написания класса. Они выпущены в React как часть v16.8.0.

useEffect ловушка может использоваться для воспроизведения поведения жизненного цикла, и useState может использоваться для хранения состояния в функциональном компоненте.

Базовый синтаксис:

useEffect(callbackFunction, [dependentProps]) => cleanupFunction

Вы можете реализовать свой вариант использования в таких хуках, как

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

useEffectтакже может возвращать функцию, которая будет запущена при размонтировании компонента. Это можно использовать для отказа от подписки на слушателей, копируя поведениеcomponentWillUnmount :

Например: componentWillUnmount

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

Чтобы useEffectобусловить определенные события, вы можете предоставить ему массив значений для проверки изменений:

Например: componentDidUpdate

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

Эквивалент крючков

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

Если вы включаете этот массив, обязательно включайте все значения из области компонента, которые меняются с течением времени (реквизиты, состояние), или вы можете в конечном итоге ссылаться на значения из предыдущих рендеров.

В использовании есть свои тонкости useEffect; проверить API Here.


До v16.7.0

Свойство функциональных компонентов состоит в том, что они не имеют доступа к функциям жизненного цикла Reacts или thisключевому слову. Вам необходимо расширить React.Componentкласс, если вы хотите использовать функцию жизненного цикла.

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

Функциональные компоненты полезны, когда вы хотите только визуализировать свой Компонент без необходимости в дополнительной логике.

Шубхам Хатри
источник
1
Как я уже сказал, у вас есть логика в вашем компоненте, и вы хотите, чтобы вы использовали функцию жизненного цикла, а вы не можете сделать это с помощью компонентов functioanl. Так что лучше используйте класс. Используйте функциональный компонент, если ваш компонент не содержит дополнительной логики
Шубхам Хатри
1
Следует отметить, что это не точный эквивалент componentDidUpdate. useEffect(() => { // action here }, [props.counter])запускается при начальной отрисовке, а componentDidUpdate - нет.
Estus Flask
1
passing an empty array as second argument triggers the callback in useEffect only after the initial renderэто звучит как грязный хакерский способ создания вещей: / надеюсь, команда react предложит что-то лучшее в будущих выпусках.
Лукас Лисис
3
так? где та часть, где вы отвечаете, как запускать код на componentwillmount?
Тоскан
59

Вы можете использовать response-pure-lifecycle, чтобы добавить функции жизненного цикла к функциональным компонентам.

Пример:

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
Что есть Grid? Я нигде не вижу его определения в вашем фрагменте кода? Если бы вы хотели использовать с этим и redux, не могли бы вы обойтись с чем-то вроде export default lifecycle(methods)(connect({},{})(ComponentName))?
Шон Клэнси
@SeanClancy Извините за поздний ответ. Фрагмент кода обновлен.
Yohann
1
Считается ли это хорошей практикой? Стоит ли мне пробовать другие решения, прежде чем я выберу это, или можно использовать его, если я считаю его самым простым?
SuperSimplePimpleDimple
9

Решение первое: вы можете использовать новый React HOOKS API. В настоящее время в React v16.8.0

Хуки позволяют использовать больше возможностей React без классов. Хуки предоставляют более прямой API к уже знакомым вам концепциям React: реквизиты, состояние, контекст, ссылки и жизненный цикл . Хуки решают все проблемы, решаемые с помощью Recompose.

Примечание автора recompose(acdlite, 25 октября 2018 г.):

Здравствуй! Я создал Recompose около трех лет назад. Примерно через год после этого я присоединился к команде React. Сегодня мы объявили предложение по Hooks. Hooks решает все проблемы, которые я пытался решить с помощью Recompose три года назад, и многие другие. Я прекращаю активное обслуживание этого пакета (за исключением, возможно, исправлений ошибок или патчей для совместимости с будущими выпусками React) и рекомендую вместо этого использовать хуки. Ваш существующий код с рекомпозицией по-прежнему будет работать, только не ждите новых функций.

Решение второе:

Если вы используете версию recomposeReact , которая не поддерживает хуки, не беспокойтесь, используйте (Пояс служебных программ React для функциональных компонентов и компонентов более высокого порядка). Можно использовать recomposeдля крепленияlifecycle hooks, state, handlers etc к функциональному компоненту.

Вот компонент без рендеринга, который присоединяет методы жизненного цикла через HOC жизненного цикла (из перекомпоновки).

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

Вы можете создавать свои собственные методы жизненного цикла.

Служебные функции

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

использование

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]);
};  
Этьен Мартин
источник
0

Если вам нужно использовать React LifeCycle, вам нужно использовать Class.

Образец:

import React, { Component } from 'react';

class Grid extends Component {

 constructor(props){
  super(props)
 }

 componentDidMount () { /* do something */ }

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

}
Габриэль Феррейра
источник
2
Я не хочу использовать этот класс.
Афтаб Навид,
3
Вопрос заключался в том, как использовать методы жизненного цикла с функциональным компонентом, а не классом.
Майк,
Теперь с React Hooks
Габриэль Феррейра
0

Вы можете использовать модуль create-response-class. Официальная документация

Конечно, сначала вы должны его установить

npm install create-react-class

Вот рабочий пример

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

если вы используете response 16.8, вы можете использовать React Hooks ... React Hooks - это функции, которые позволяют вам «подключаться» к функциям состояния и жизненного цикла React из функциональных компонентов ... docs

WAEX
источник