函数组件中的ReactJS生命周期方法


133

与其在一个类中编写组件,不如使用函数语法。

如何覆盖componentDidMountcomponentWillMount内部功能部件?
可能吗?

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

Answers:


148

编辑:通过引入,Hooks可以实现行为的生命周期类型以及功能组件中的状态。目前

挂钩是一项新的功能建议,使您无需编写类即可使用状态和其他React功能。它们作为v16.8.0的一部分在React中发布

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组件来做到这一点。所以最好利用类。当您的组件不包含任何额外逻辑时,请使用功能组件
Shubham Khatri

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

您可以使用react-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的更多功能。 挂钩为您已经知道的React概念提供了更直接的API:道具,状态,上下文,引用和生命周期。Hooks解决了Recompose解决的所有问题。

recompose(acdlite,2018年10月25日)作者的注释:

嗨!我大约在三年前创建了Recompose。大约一年后,我加入了React团队。今天,我们宣布了有关Hooks的提案。Hooks解决了三年前我尝试使用Recompose解决的所有问题,并且除此之外。我将停止对该程序包的积极维护(可能不包括与将来的React版本兼容的错误修正或补丁),并建议人们改用Hooks。使用Recompose的现有代码仍然可以使用,只是不要期望有任何新功能。

解决方案二:

如果您使用的是不支持钩子recompose的React 版本,请不要担心,而应使用(功能组件和高阶组件的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]);
};  

2

根据文档:

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

useEffect(() => {


});

查看React文档


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
问题是如何将生命周期方法与功能组件而不是类一起使用。
Mike

现在,有了React Hooks
Gabriel Ferreira

0

您可以使用create-react-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

如果您使用react 16.8,则可以使用react Hooks ... React Hooks是使您可以“挂钩”功能组件中的React状态和生命周期功能的函数... docs

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.