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

IT技术 reactjs redux
2021-03-28 05:41:08

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

如何覆盖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>  
    )
}
6个回答

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

Hooks 是一个新的特性提案,它可以让你在不编写类的情况下使用状态和其他 React 特性。它们作为v16.8.0的一部分在 React 中发布

useEffecthook 可用于复制生命周期行为,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

如果您包含此数组,请确保包含随时间变化的组件作用域中的所有值(props、状态),否则您最终可能会引用先前渲染中的值。

使用有一些微妙之处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>  
    )
  }
}

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

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

您可以使用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我没有看到它在您的代码片段中的任何地方定义?如果您也想将 redux 与此一起使用,您可以使用类似的东西export default lifecycle(methods)(connect({},{})(ComponentName))吗?
2021-05-27 05:41:08
这被认为是一种好的做法吗?在我找到这个解决方案之前,我应该尝试不同的解决方案,还是如果我觉得最简单就可以使用它?
2021-06-05 05:41:08
@SeanClancy 抱歉回复晚了。代码片段已更新。
2021-06-07 05:41:08

您可以使用钩子制作自己的“生命周期方法”,以最大限度地怀旧。

实用功能:

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

解决方案一: 您可以使用新的 react 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 的提案。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);

根据文档:

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

useEffect(() => {


});

参见React 文档