简体   繁体   English

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

[英]ReactJS lifecycle method inside a function Component

Instead of writing my components inside a class, I'd like to use the function syntax.我不想在类中编写组件,而是使用函数语法。

How do I override componentDidMount , componentWillMount inside function components?如何在函数组件中覆盖componentDidMountcomponentWillMount
Is it even possible?甚至可能吗?

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

Edit: With the introduction of Hooks it is possible to implement a lifecycle kind of behavior as well as the state in the functional Components.编辑:随着Hooks的引入,可以实现生命周期类型的行为以及功能组件中的状态。 Currently目前

Hooks are a new feature proposal that lets you use state and other React features without writing a class. Hooks 是一个新的特性提议,它允许你在不编写类的情况下使用状态和其他 React 特性。 They are released in React as a part of v16.8.0它们作为v16.8.0的一部分在 React 中发布

useEffect hook can be used to replicate lifecycle behavior, and useState can be used to store state in a function component. useEffect hook 可用于复制生命周期行为,而useState可用于将状态存储在功能组件中。

Basic syntax:基本语法:

useEffect(callbackFunction, [dependentProps]) => cleanupFunction

You can implement your use case in hooks like您可以在钩子中实现您的用例,例如

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 can also return a function that will be run when the component is unmounted. useEffect还可以返回一个函数,该函数将在卸载组件时运行。 This can be used to unsubscribe to listeners, replicating the behavior of componentWillUnmount :这可用于取消订阅侦听器,复制componentWillUnmount的行为:

Eg: componentWillUnmount例如:componentWillUnmount

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

To make useEffect conditional on specific events, you may provide it with an array of values to check for changes:要使useEffect以特定事件为条件,您可以为其提供一组值以检查更改:

Eg: componentDidUpdate例如:componentDidUpdate

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

Hooks Equivalent挂钩等效

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

If you include this array, make sure to include all values from the component scope that change over time (props, state), or you may end up referencing values from previous renders.如果包含此数组,请确保包含组件范围内随时间变化的所有值(道具、状态),否则您最终可能会引用先前渲染中的值。

There are some subtleties to using useEffect ;使用useEffect有一些微妙之处; check out the API Here .Here查看 API。


Before v16.7.0 v16.7.0之前

The property of function components is that they don't have access to Reacts lifecycle functions or the this keyword.函数组件的属性是它们无法访问 Reacts 生命周期函数或this关键字。 You need to extend the React.Component class if you want to use the lifecycle function.如果要使用生命周期功能,则需要扩展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>  
    )
  }
}

Function components are useful when you only want to render your Component without the need of extra logic.当您只想渲染组件而不需要额外的逻辑时,函数组件很有用。

You can use react-pure-lifecycle to add lifecycle functions to functional components.您可以使用react-pure-lifecycle为功能组件添加生命周期功能。

Example:例子:

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

You can make your own "lifecycle methods" using hooks for maximum nostalgia.您可以使用钩子制作自己的“生命周期方法”,以获得最大的怀旧感。

Utility functions:实用功能:

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, []);
};

Usage:用法:

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

Solution One: You can use new react HOOKS API.解决方案一:您可以使用新的 react HOOKS API。 Currently in React v16.8.0目前在React v16.8.0

Hooks let you use more of React's features without classes. Hooks 让你可以在没有类的情况下使用更多 React 的特性。 Hooks provide a more direct API to the React concepts you already know: props, state, context, refs, and lifecycle . Hooks 为你已经知道的 React 概念提供了更直接的 API:props、state、context、refs 和生命周期 Hooks solves all the problems addressed with Recompose. Hooks 解决了 Recompose 解决的所有问题。

A Note from the Author of recompose (acdlite, Oct 25 2018): recompose作者的注释(acdlite,2018 年 10 月 25 日):

Hi!你好! I created Recompose about three years ago.大约三年前,我创建了 Recompose。 About a year after that, I joined the React team.大约一年后,我加入了 React 团队。 Today, we announced a proposal for Hooks.今天,我们宣布了 Hooks 的提案。 Hooks solves all the problems I attempted to address with Recompose three years ago, and more on top of that. Hooks 解决了我三年前尝试使用 Recompose 解决的所有问题,除此之外还有更多问题。 I will be discontinuing active maintenance of this package (excluding perhaps bugfixes or patches for compatibility with future React releases), and recommending that people use Hooks instead.我将停止对该包的积极维护(可能不包括错误修复或与未来 React 版本兼容的补丁),并建议人们改用 Hooks。 Your existing code with Recompose will still work, just don't expect any new features.您使用 Recompose 的现有代码仍然可以工作,只是不要期望任何新功能。

Solution Two:解决方案二:

If you are using react version that does not support hooks, no worries, use recompose (A React utility belt for function components and higher-order components.) instead.如果您使用的是不支持 hooks 的 react 版本,不用担心,请使用recompose (用于功能组件和高阶组件的 React 实用工具带。)。 You can use recompose for attaching lifecycle hooks, state, handlers etc to a function component.您可以使用recomposelifecycle hooks, state, handlers etc附加到功能组件。

Here's a render-less component that attaches lifecycle methods via the lifecycle HOC (from recompose).这是一个无渲染组件,它通过生命周期 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);

componentDidMount组件DidMount

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

componentWillMount组件WillMount

useEffect(()=>{

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

componentDidUpdate组件DidUpdate

useEffect(()=>{

    //code here
    // when userName state change it will call     
},[userName])

Short and sweet answer简短而甜蜜的答案

componentDidMount组件DidMount

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

componentWillUnmount组件WillUnmount

useEffect(()=>{

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

componentDidUpdate组件DidUpdate

useEffect(()=>{

    //code here
    // when userName state change it will call     
},[userName])

According to the documentation:根据文档:

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

useEffect(() => {


});

see React documentation参见反应文档

You can make use of create-react-class module.您可以使用 create-react-class 模块。 Official documentation官方文档

Of course you must first install it当然你必须先安装它

npm install create-react-class

Here is a working example这是一个工作示例

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

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

import React, { useState, useEffect } from "react";

const Counter = () => {
  const [count, setCount] = useState(0);
  const [count2, setCount2] = useState(0);

  // componentDidMount
  useEffect(() => {
    console.log("The use effect ran");
  }, []);

  // // componentDidUpdate
  useEffect(() => {
    console.log("The use effect ran");
  }, [count, count2]);

  // componentWillUnmount
  useEffect(() => {
    console.log("The use effect ran");
    return () => {
      console.log("the return is being ran");
    };
  }, []);

  useEffect(() => {
    console.log(`The count has updated to ${count}`);
    return () => {
      console.log(`we are in the cleanup - the count is ${count}`);
    };
  }, [count]);

  return (
    <div>
      <h6> Counter </h6>
      <p> current count: {count} </p>
      <button onClick={() => setCount(count + 1)}>increment the count</button>
      <button onClick={() => setCount2(count2 + 1)}>increment count 2</button>
    </div>
  );
};

export default Counter;

Instead of writing my components inside a class, I'd like to use the function syntax.与其将我的组件写在一个类中,我想使用函数语法。

How do I override componentDidMount , componentWillMount inside function components?如何重写componentDidMountcomponentWillMount内部功能部件?
Is it even possible?可能吗?

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM