React16 abolished componentWillReceiveProps, so how do components re-render when they receive a new props?

now write a countdown component, and I think the countdown starts again when the parent passes it to the countdown component. The problem is that there is no trigger, and then the getDerivedStateFromProps, is used, but the time does not move all the time.
I think the reason is that the code in
looks like componentDidUpdate re-tick (), but setState, in tick leads to an endless loop

class Countdown extends React.Component {
    state = {
        count: this.props.count
    }
    timer = null
    tick = () => {
        let count = this.state.count;
        if (typeof count !== "number" || count <= 0) {
            throw new Error(`prop "count" must be positive integer`);
        }
        this.timer = setInterval(() => {
            if (count <= 0) {
                clearInterval(this.timer);
                if (typeof this.props.callback === "function") {
                    this.props.callback();
                }
                return;
            }
            count--;
            this.setState({ count });
        }, 1000);
    }
    componentDidMount() {
        this.tick();
    }
    static getDerivedStateFromProps(nextProps) {
        return {
            count:nextProps.count
        }
    }
    componentDidUpdate() {
        clearInterval(this.timer);
        this.tick();
    }
    componentWillUnmount() {
        clearInterval(this.timer);
    }
    render() {
        const { style, className, dayText = "" } = this.props;
        const d = Math.floor(this.state.count / 60 / 60 / 24);
        let h = Math.floor(this.state.count / 60 / 60 - d * 24);
        h = `0${h}`.slice(-2);
        let m = Math.floor(this.state.count / 60 - h * 60 - d * 24 * 60);
        m = `0${m}`.slice(-2);
        let s = this.state.count - d * 24 * 60 * 60 - h * 60 * 60 - m * 60;
        s = `0${s}`.slice(-2);
        return (
            <span className={`count-down-wrapper ${className}`} style={style}>
                <i className="count-down-day">
                    {d}
                    <em className="count-down-day-text">{d > 0 ? dayText : null}</em>
                </i>
                <i className="count-down-hours">{h}</i>
                <i className="count-down-symbol">:</i>
                <i className="count-down-minutes">{m}</i>
                <i className="count-down-symbol">:</i>
                <i className="count-down-seconds">{s}</i>
            </span>
        );
    }
}
Aug.03,2021

Hello, you can keep a copy of props's count in state as a comparison, and in getDerivedStateFromProps, only call tick to recalculate when the count changes. In addition, delete componentDidUpdate.


in this case, it is recommended to remove the component:

  • the business logic for the countdown is written in the parent component.
  • The
  • subcomponent can be made into a stateless component that is only used to render the view.

Why do you want to clear the timer in componentDidUpdate and turn on a new timer?

The

problem is here, not in getDerivedStateFromProps .

these new methods were proposed in 16.3, and that method will not be removed in the 16.x version. Updates are mandatory only in No. 17 Middle School.


to add a comparison between the current count and the previous count in componenDidUpdate, call

only if it has been changed.
Menu