簡體   English   中英

將 DidMount/DidUnmount 從 react class 組件轉換為功能組件

[英]Convert DidMount/DidUnmount from react class component to functional component

我正在寫一個簡單的計時器應用程序來做出反應。 計時器不屬於反應組件,但將在多個計時器組件之間共享。 作為組件安裝的一部分,我用我的通用計時器注冊了反應組件,並用“滴答聲”更新組件。

我的期望是當組件被安裝時,我將它注冊到我的主計時器並開始接收滴答聲。 當我卸載組件時,它被取消注冊。 這在使用 react class 組件時非常有效(如下面的代碼所示)。

但是,當我嘗試使用功能組件和 useEffect 執行此操作時,我無法獲得預期的行為。 我在下面的代碼中列出了 useEffect 的兩種方法,但都不是我想要的。 我已經在下面的代碼中解釋了我的問題。

顯然我想使用最新的反應(功能組件),但我還沒有讓它們在這種情況下正常工作。

import * as React from 'react';
import { register, deregister, formatMsToTime } from '../logic/Timer';

export default class Timer extends React.Component {
    constructor(props) {
        super(props);
        const { name, initialTime } = props;
        this.name = name;

        this.state = {
            time: initialTime,
        };
    }

    componentDidMount() {
        register(this.name, (elapsed) => this.setState(state => ({ time: state.time - elapsed })));
    }

    componentDidUnmount() {
        deregister(this.name);
    }

    render() {
        return (<>
            {formatMsToTime(this.state.time)}
        </>
        );
    }
}

export default function Timer(props) {
    const [time, setTime] = useState(props.initialTime);

    //useEffect option #1
    /*
        This technically works, the timer is updated properly and shows the countdown I'm expecting.
        However, this calls register/deregister with every render of the component, which I don't want.
        Render is called with every tick of the timer, which happens every 50ms (so, a lot). 
    */
    useEffect(() => {
        register(props.name, (elapsed) => setTime(time - elapsed));

        return () => {
            deregister(props.name);
        }
    })

    //useEffect option #2
    /*
        This works for about .1 seconds. On the first render, setTime refers to a function used for setting the state, and it gets called with the elapsed time.
        On the second render, the state variable time and its setter are overwritten, and 'setTime' in useEffect no longer refers to the correct setTime function.
    */
    useEffect(() => {
        register(props.name, (elapsed) => setTime(time - elapsed));

        return () => {
            deregister(props.name);
        }
    }, [])

    return (<>
        {formatMsToTime(time)}
    </>);
}

您可能需要功能更新程序方法

   useEffect(() => {
        register(props.name, (elapsed) => setTime(t => t - elapsed));
        // replace setTime(time - elapsed)) with setTime(t => t - elapsed)

        return () => {
            deregister(props.name);
        }
    }, []) // looks like props.name dependency need to be added

希望它有幫助,我鼓勵你通過新的 React 文檔到 go,他們會幫助很多,干杯

編輯:鏈接到與此答案更相關的功能更新程序方法,感謝@Michael將其包含在評論中以改進答案

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM