Метод життєвого циклу ReactJS всередині функції Компонент


135

Замість того, щоб писати мої компоненти всередині класу, я хотів би використати синтаксис функції.

Як перевизначити 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
Функціональні компоненти не повинні мати методів життєвого циклу. тому що вони є лише функціями. а функції не мають методів. для цього є заняття
лавина1

Відповіді:


149

Редагувати: Завдяки впровадженню 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:

Напр .: компонентWillUnmount

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

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

Напр., КомпонентDidUpdate

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
Як я вже сказав, у вас є логіка у вашому компоненті, і ви вимагаєте, щоб ви використовували функцію життєвого циклу, і ви не можете робити це з функціональними компонентами. Тож краще скористайтеся класом. Використовуйте функціональний компонент, коли ваш компонент не містить зайвої логіки
Shubham Khatri

1
Слід зазначити, що це не точний еквівалент компонентаDidUpdate. useEffect(() => { // action here }, [props.counter])запускається при початковому візуалізації, поки компонентDidUpdate не робить.
колба

1
passing an empty array as second argument triggers the callback in useEffect only after the initial renderце звучить як брудний хакітський спосіб створення матеріалів: / сподіваємось, команда реагує придумає щось краще в майбутніх випусках.
Лукас Лейсіс

3
так? де частина, де ви відповідаєте, як запустити код на компонентwillmount?
Тоскан

59

Ви можете використовувати реакційний чистий життєвий цикл, щоб додати функції життєвого циклу до функціональних компонентів.

Приклад:

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? Я не бачу, щоб це було визначено ніде у вашому фрагменті коду? Якби ви хотіли скористатися редуксом і для цього, чи могли б ви піти з чимось подібним export default lifecycle(methods)(connect({},{})(ComponentName))?
Шон Клансі

@SeanClancy Вибачте за несвоєчасну відповідь. Фрагмент коду було оновлено.
Йоханн

1
Це вважається хорошою практикою? Чи варто спробувати різні рішення, перш ніж я досягти цього, чи це нормально використовувати, якщо мені це найлегше?
SuperSimplePimpleDimple

9

Перше рішення: Ви можете використовувати новий реакційний HOOKS API. Наразі в React v16.8.0

Гачки дозволяють вам використовувати більше функцій React без класів. Гачки забезпечують більш прямий API для концепцій React, які ви вже знаєте: реквізит, стан, контекст, перегляд та життєвий цикл . Гачки вирішують усі проблеми, вирішені з Рекомендувати.

Нотатка автора recompose(acdlite, 25 жовтня 2018 р.):

Привіт! Я створив Рекомендувати близько трьох років тому. Приблизно через рік я приєднався до команди React. Сьогодні ми оголосили пропозицію щодо Гачків. Гачки вирішують усі проблеми, з якими я намагався вирішити Рекомендувати три роки тому, і більше того. Я припиняю активне обслуговування цього пакету (виключаючи, можливо, виправлення чи виправлення для сумісності з майбутніми випусками React), і рекомендую людям замість цього використовувати Гаки. Ваш наявний код із "Репонувати" все одно буде працювати, просто не сподівайтесь на нові функції.

Рішення друге:

Якщо ви використовуєте реакційну версію, яка не підтримує гачки, не хвилюйтесь, скористайтеся recompose(Режим утиліти 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
Я не хочу використовувати клас.
Aftab Naveed

3
Питання полягало в тому, як використовувати методи життєвого циклу з функціональним компонентом, а не класом.
Майк

Тепер, з React Hooks
Габріель Феррейра

0

Ви можете використовувати модуль класу create-react. Офіційна документація

Звичайно, спочатку потрібно встановити його

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

якщо ви використовуєте реакцію 16.8, ви можете використовувати реакційні гачки ... Реактивні гачки - це функції, які дозволяють вам "зачепитись" на функції реагування стану та життєвого циклу від компонентів функції ... документи

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.