【问题标题】:ReactJS lifecycle method inside a function Component函数组件内的 ReactJS 生命周期方法
【发布时间】:2017-06-12 18:20:04
【问题描述】:

我不想在类中编写组件,而是使用函数语法。

如何在函数组件中覆盖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>  
    )
}

【问题讨论】:

  • 功能组件不应该有生命周期方法。因为它们只是函数。和函数没有方法。有相应的课程

标签: reactjs redux


【解决方案1】:

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

Hooks 是一项新功能提案,可让您使用状态和其他 无需编写类即可反应特性。它们作为 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>  
    )
  }
}

当你只想渲染你的组件而不需要额外的逻辑时,函数组件很有用。

【讨论】:

  • 正如我所说,您的组件中有一个逻辑,并且您要求您使用生命周期功能,而您不能使用功能组件来做到这一点。所以最好利用类。当你的组件不包含额外的逻辑时使用函数式组件
  • 应该注意这不是与 componentDidUpdate 完全等效的。 useEffect(() =&gt; { // action here }, [props.counter]) 会在初始渲染时触发,而 componentDidUpdate 不会。
  • passing an empty array as second argument triggers the callback in useEffect only after the initial render 这听起来像是一种肮脏的 hacky 构建方式:/ 希望 React 团队在未来的版本中能提出更好的东西。
  • 所以?您回答如何在 componentwillmount 上运行代码的部分在哪里?
【解决方案2】:

您可以使用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);

【讨论】:

  • 什么是Grid?我在您的代码 sn-p 中的任何地方都没有看到它定义?如果你也想使用 redux 的话,你可以用 export default lifecycle(methods)(connect({},{})(ComponentName)) 之类的东西吗?
  • @SeanClancy 抱歉回复晚了。代码 sn-p 已更新。
  • 这是一个好的做法吗?在我找到这个解决方案之前我应该​​尝试不同的解决方案,还是如果我觉得它最简单就可以使用它?
【解决方案3】:

您可以使用hooks 制作自己的“生命周期方法”,以获得最大的怀旧感。

实用功能:

import { useEffect, useRef } from "react";

export const useComponentDidMount = handler => {
  return useEffect(() => handler(), []);
};

export const useComponentDidUpdate = (handler, deps) => {
  const isInitialMount = useRef(true);

  useEffect(() => {
    if (isInitialMount.current) {
      isInitialMount.current = false;

      return;
    }

    return handler();
  }, deps);
};

export const useComponentWillUnmount = handler => {
  return useEffect(() => handler, []);
};

用法:

import {
  useComponentDidMount,
  useComponentDidUpdate,
  useComponentWillUnmount
} from "./utils";

export const MyComponent = ({ myProp }) => {
  useComponentDidMount(() => {
    console.log("Component did mount!");
  });

  useComponentDidUpdate(() => {
    console.log("Component did update!");
  });

  useComponentDidUpdate(() => {
    console.log("myProp did update!");
  }, [myProp]);

  useComponentWillUnmount(() => {
    console.log("Component will unmount!");
  });

  return <div>Hello world</div>;
};  

【讨论】:

    【解决方案4】:

    解决方案一: 您可以使用新的反应 HOOKS API。目前在 React v16.8.0

    Hooks 让你可以在没有类的情况下使用 React 的更多功能。 Hooks 为你已经知道的 React 概念提供了更直接的 API:props、state、context、refs 和 生命周期。 Hooks 解决了 Recompose 解决的所有问题。

    recompose(acdlite,2018 年 10 月 25 日)的作者致辞:

    嗨!大约三年前,我创建了 Recompose。大约一年后 那,我加入了 React 团队。今天,我们宣布了一项提案 挂钩。 Hooks 解决了我试图解决的所有问题 三年前重组,更重要的是。我将要 停止对该软件包的主动维护(可能不包括 与未来 React 版本兼容的错误修复或补丁),以及 建议人们改用 Hooks。您现有的代码 Recompose 仍然可以工作,只是不要期待任何新功能。

    解决方案二:

    如果您使用的是不支持 hooks 的 react 版本,不用担心,请改用 recompose(用于功能组件和高阶组件的 React 实用工具带。)。您可以使用recomposelifecycle hooks, state, handlers etc 附加到功能组件。

    这是一个无渲染组件,它通过生命周期 HOC(来自 recompose)附加 生命周期方法

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

    【讨论】:

      【解决方案5】:

      根据文档:

      import React, { useState, useEffect } from 'react'
      // Similar to componentDidMount and componentDidUpdate:
      
      useEffect(() => {
      
      
      });
      

      React documentation

      【讨论】:

        【解决方案6】:

        componentDidMount

        useEffect(()=>{
           // code here
        })
        

        componentWillMount

        useEffect(()=>{
        
           return ()=>{ 
                        //code here
                      }
        })
        

        componentDidUpdate

        useEffect(()=>{
        
            //code here
            // when userName state change it will call     
        },[userName])
        

        【讨论】:

        • @Somitya - 你是否应该写“componentWillUnmount”而不是“componentWillMount”?
        【解决方案7】:

        您可以使用 create-react-class 模块。 Official documentation

        当然要先安装

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

        【讨论】:

          【解决方案8】:

          如果你使用 react 16.8,你可以使用 react Hooks... React Hooks 是让你从函数组件中“挂钩”到 React 状态和生命周期特性的函数...... docs

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-10
            • 1970-01-01
            • 2020-07-20
            • 2020-11-10
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多