ReactJS lifecycle method ภายในคอมโพเนนต์ของฟังก์ชัน


136

แทนที่จะเขียนส่วนประกอบของฉันภายในคลาสฉันต้องการใช้ไวยากรณ์ของฟังก์ชันแทน

ฉันจะแทนที่วิธี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>  
    )
}

1
ส่วนประกอบที่ใช้งานได้ไม่ควรมีวิธีวงจรชีวิต เพราะเป็นเพียงฟังก์ชัน และฟังก์ชันไม่มีเมธอด มีคลาสสำหรับสิ่งนั้น
หิมะถล่ม 1

คำตอบ:


151

แก้ไข:ด้วยการแนะนำHooksนี้เป็นไปได้ที่จะใช้ลักษณะการทำงานของวงจรชีวิตเช่นเดียวกับสถานะในส่วนประกอบการทำงาน ปัจจุบัน

Hooks เป็นข้อเสนอคุณสมบัติใหม่ที่ให้คุณใช้สถานะและคุณสมบัติการตอบสนองอื่น ๆ โดยไม่ต้องเขียนคลาส พวกเขาถูกปล่อยออกมาใน React เป็นส่วนหนึ่งของv16.8.0

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

หากคุณรวมอาร์เรย์นี้ตรวจสอบให้แน่ใจว่าได้รวมค่าทั้งหมดจากขอบเขตคอมโพเนนต์ที่เปลี่ยนแปลงตลอดเวลา (อุปกรณ์ประกอบฉากสถานะ) มิฉะนั้นคุณอาจต้องอ้างอิงค่าจากการแสดงผลก่อนหน้านี้

มีรายละเอียดปลีกย่อยบางอย่างในการใช้useEffect; Hereตรวจสอบของ API


ก่อน 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ฟังดูเหมือนเป็นวิธีแฮ็กที่สกปรกในการสร้างสิ่งต่างๆ: / หวังว่าทีมตอบสนองจะคิดสิ่งที่ดีกว่าในรุ่นต่อ ๆ ไป
Lukas Liesis

3
ดังนั้น? ส่วนที่คุณตอบวิธีรันโค้ดบน componentwillmount อยู่ที่ไหน
ทศกัณฐ์

59

คุณสามารถใช้react-pure-lifecycleเพื่อเพิ่มฟังก์ชัน 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))หรือไม่?
Sean Clancy

@SeanClancy ขออภัยที่ตอบช้า อัปเดตข้อมูลโค้ดแล้ว
Yohann

1
นี่ถือเป็นแนวทางปฏิบัติที่ดีหรือไม่? ฉันควรลองใช้วิธีแก้ปัญหาอื่นก่อนที่ฉันจะไปถึงวิธีนี้หรือจะใช้วิธีนี้ได้หรือไม่ถ้าฉันคิดว่าง่ายที่สุด
SuperSimplePimpleDimple

9

แนวทางที่หนึ่ง: คุณสามารถใช้ react HOOKS API ใหม่ได้ ปัจจุบันอยู่ในReact v16.8.0

Hooks ช่วยให้คุณใช้คุณสมบัติของ React ได้มากขึ้นโดยไม่มีคลาส Hooks มอบ API ที่ตรงกว่าให้กับแนวคิด React ที่คุณรู้จักอยู่แล้ว: อุปกรณ์ประกอบฉากสถานะบริบทอ้างอิงและวงจรชีวิตวงจรชีวิตHooks ช่วยแก้ปัญหาทั้งหมดด้วย Recompose

หมายเหตุจากผู้เขียนrecompose(acdlite, 25 ต.ค. 2018):

ไฮ! ฉันสร้าง Recompose เมื่อประมาณสามปีที่แล้ว ประมาณหนึ่งปีหลังจากนั้นฉันก็เข้าร่วมทีม React วันนี้เราประกาศข้อเสนอสำหรับ Hooks Hooks ช่วยแก้ปัญหาทั้งหมดที่ฉันพยายามแก้ไขด้วย Recompose เมื่อสามปีที่แล้วและยิ่งไปกว่านั้น ฉันจะหยุดการบำรุงรักษาที่ใช้งานอยู่ของแพคเกจนี้ (ยกเว้นการแก้ไขข้อบกพร่องหรือแพตช์สำหรับความเข้ากันได้กับรุ่น React ในอนาคต) และแนะนำให้ผู้คนใช้ Hooks แทน โค้ดที่มีอยู่ของคุณด้วย Recompose จะยังใช้งานได้อย่าคาดหวังว่าจะมีคุณสมบัติใหม่

แนวทางที่สอง:

หากคุณกำลังใช้รุ่น react ที่ไม่รองรับ hook ไม่ต้องกังวลให้ใช้recompose(สายพานยูทิลิตี้ A React สำหรับส่วนประกอบฟังก์ชันและส่วนประกอบลำดับที่สูงกว่า) แทน คุณสามารถใช้recomposeสำหรับติดlifecycle 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);

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


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 state และอายุการใช้งานจากส่วนประกอบของฟังก์ชัน ... docs

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.