ReactJS-Lebenszyklusmethode innerhalb einer Funktionskomponente


133

Anstatt meine Komponenten in eine Klasse zu schreiben, möchte ich stattdessen die Funktionssyntax verwenden.

Wie überschreiben ich componentDidMount, componentWillMountinnerhalb Funktionskomponenten?
Ist es überhaupt möglich?

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
Funktionskomponenten sollten keine Lebenszyklusmethoden haben. weil sie nur Funktionen sind. und Funktionen haben keine Methoden. gibt es Klassen für das
avalanche1

Antworten:


148

Bearbeiten: Mit der Einführung Hooksist es möglich, ein Lebenszyklus-Verhalten sowie den Status in den Funktionskomponenten zu implementieren. Zur Zeit

Hooks sind ein neuer Funktionsvorschlag, mit dem Sie Status- und andere Reaktionsfunktionen verwenden können, ohne eine Klasse zu schreiben. Sie werden in React als Teil von Version 16.8.0 veröffentlicht

useEffectDer Hook kann zum Replizieren des Lebenszyklusverhaltens und useStatezum Speichern des Status in einer Funktionskomponente verwendet werden.

Grundlegende Syntax:

useEffect(callbackFunction, [dependentProps]) => cleanupFunction

Sie können Ihren Anwendungsfall in Hooks wie implementieren

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

useEffectkann auch eine Funktion zurückgeben, die ausgeführt wird, wenn die Komponente nicht bereitgestellt wird. Dies kann verwendet werden, um Hörer abzubestellen und das Verhalten von componentWillUnmount:

Beispiel: componentWillUnmount

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

Um useEffectvon bestimmten Ereignissen abhängig zu machen , können Sie eine Reihe von Werten bereitstellen, um nach Änderungen zu suchen:

Beispiel: componentDidUpdate

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

Haken äquivalent

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

Wenn Sie dieses Array einschließen, stellen Sie sicher, dass alle Werte aus dem Komponentenbereich enthalten sind, die sich im Laufe der Zeit ändern (Requisiten, Status). Andernfalls verweisen Sie möglicherweise auf Werte aus früheren Renderings.

Es gibt einige Feinheiten bei der Verwendung useEffect; Überprüfen Sie die API Here.


Vor v16.7.0

Die Eigenschaft von Funktionskomponenten besteht darin, dass sie keinen Zugriff auf Reacts-Lebenszyklusfunktionen oder das thisSchlüsselwort haben. Sie müssen die React.ComponentKlasse erweitern, wenn Sie die Lebenszyklusfunktion verwenden möchten.

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

Funktionskomponenten sind nützlich, wenn Sie Ihre Komponente nur ohne zusätzliche Logik rendern möchten.


1
Wie gesagt, Sie haben eine Logik in Ihrer Komponente und Ihre Anforderung möchte, dass Sie eine Lebenszyklusfunktion verwenden, und Sie können dies nicht mit Funktionskomponenten tun. Nutzen Sie also besser die Klasse. Verwenden Sie eine Funktionskomponente, wenn Ihre Komponente keine zusätzliche Logik enthält
Shubham Khatri

1
Es ist zu beachten, dass dies kein genaues Äquivalent zu componentDidUpdate ist. useEffect(() => { // action here }, [props.counter])wird beim ersten Rendern ausgelöst, während componentDidUpdate dies nicht tut.
Estus Flask

1
passing an empty array as second argument triggers the callback in useEffect only after the initial renderDas klingt nach einer schmutzigen, hackigen Art, Dinge zu bauen: / Hoffentlich wird das Reaktionsteam in zukünftigen Versionen etwas Besseres einfallen lassen.
Lukas Liesis

3
so? Wo ist der Teil, in dem Sie antworten, wie Code auf componentwillmount ausgeführt wird?
Toskan

59

Sie können den React-Pure-Lifecycle verwenden , um Funktionskomponenten Lifecycle-Funktionen hinzuzufügen.

Beispiel:

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
Was ist Grid? Ich sehe es nirgendwo in Ihrem Code-Snippet definiert? Wenn Sie auch hier Redux verwenden möchten, könnten Sie dann mit so etwas davonkommen export default lifecycle(methods)(connect({},{})(ComponentName))?
Sean Clancy

@ SeanClancy Entschuldigung für die verspätete Antwort. Das Code-Snippet wurde aktualisiert.
Yohann

1
Ist dies eine gute Praxis? Sollte ich verschiedene Lösungen ausprobieren, bevor ich nach dieser greife, oder ist es in Ordnung, sie zu verwenden, wenn ich sie am einfachsten finde?
SuperSimplePimpleDimple

9

Lösung 1: Sie können die neue React HOOKS API verwenden. Derzeit in React v16.8.0

Mit Hooks können Sie mehr Funktionen von React ohne Klassen verwenden. Hooks bieten eine direktere API für die bereits bekannten React-Konzepte: Requisiten, Status, Kontext, Refs und Lebenszyklus . Hooks löst alle mit Recompose angesprochenen Probleme.

Eine Anmerkung des Autors von recompose(acdlite, 25. Oktober 2018):

Hallo! Ich habe Recompose vor ungefähr drei Jahren erstellt. Ungefähr ein Jahr später trat ich dem React-Team bei. Heute haben wir einen Vorschlag für Hooks angekündigt. Hooks löst alle Probleme, die ich vor drei Jahren mit Recompose zu lösen versucht habe, und noch mehr. Ich werde die aktive Wartung dieses Pakets einstellen (ausgenommen möglicherweise Bugfixes oder Patches, um die Kompatibilität mit zukünftigen React-Versionen zu gewährleisten) und empfehlen, stattdessen Hooks zu verwenden. Ihr vorhandener Code mit Recompose funktioniert weiterhin. Erwarten Sie jedoch keine neuen Funktionen.

Lösung Zwei:

Wenn Sie recomposeeine React- Version verwenden, die keine Hooks unterstützt, verwenden Sie stattdessen (A React Utility Belt für Funktionskomponenten und Komponenten höherer Ordnung.). Sie können recomposezum Anhängen lifecycle hooks, state, handlers etcan eine Funktionskomponente verwenden.

Hier ist eine Komponente ohne Rendering, die Lebenszyklusmethoden über das Lebenszyklus-HOC (von der Neuzusammenstellung) anfügt.

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

Sie können Ihre eigenen Lebenszyklusmethoden erstellen.

Dienstprogrammfunktionen

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

Verwendung

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

Laut Dokumentation:

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

useEffect(() => {


});

Siehe React-Dokumentation


0

Wenn Sie React LifeCycle verwenden müssen, müssen Sie Class verwenden.

Stichprobe:

import React, { Component } from 'react';

class Grid extends Component {

 constructor(props){
  super(props)
 }

 componentDidMount () { /* do something */ }

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

}

2
Ich möchte die Klasse nicht benutzen.
Aftab Naveed

3
Die Frage war, wie Lebenszyklusmethoden mit einer Funktionskomponente und nicht mit einer Klasse verwendet werden.
Mike

Jetzt mit React Hooks
Gabriel Ferreira

0

Sie können das Modul create-react-class verwenden. Offizielle Dokumentation

Natürlich müssen Sie es zuerst installieren

npm install create-react-class

Hier ist ein Arbeitsbeispiel

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

Wenn Sie React 16.8 verwenden, können Sie React Hooks verwenden. React Hooks sind Funktionen, mit denen Sie sich in Funktionsstatus- und Lebenszyklusfunktionen aus Funktionskomponenten einbinden können

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.