在 React 中基于子组件状态禁用按钮

Disabling button based on child component state in React

我正在使用倒计时组件作为子组件。 我想 disable/reable 一个基于计数器状态值的按钮,但我似乎无法正确读取该值。

这是我试过的。 这是倒计时组件:

import React from "react";
import PropTypes from "prop-types";


export default class Counter extends React.Component {
  constructor() {
    super();
    this.state = { time: {}, seconds: 15 };
    this.timer = 0;
    this.startTimer = this.startTimer.bind(this);
    this.countDown = this.countDown.bind(this);
  }

  secondsToTime(secs){
    let hours = Math.floor(secs / (60 * 60));

    let divisor_for_minutes = secs % (60 * 60);
    let minutes = Math.floor(divisor_for_minutes / 60);

    let divisor_for_seconds = divisor_for_minutes % 60;
    let seconds = Math.ceil(divisor_for_seconds);

    let obj = {
      "h": hours,
      "m": minutes,
      "s": seconds
    };
    return obj;
  }

  componentDidMount() {
    let timeLeftVar = this.secondsToTime(this.state.seconds);
    this.setState({ time: timeLeftVar });
  }

  startTimer() {
    if (this.timer === 0 && this.state.seconds > 0) {
      this.timer = setInterval(this.countDown, 1000);
    } else if ((this.timer === 0 && this.state.seconds === 0)){
      this.state.seconds = 15;
      this.timer = setInterval(this.countDown, 1000);
    }
  }

  countDown() {
    // Remove one second, set state so a re-render happens.
    let seconds = this.state.seconds - 1;
    this.setState({
      time: this.secondsToTime(seconds),
      seconds: seconds,
    });
    
    // Check if we're at zero.
    if (seconds === 0) { 
      clearInterval(this.timer);
      this.timer = 0;
      console.log("counter is 0");
      console.log(this.state.seconds);
      console.log(this.timer);
    }
  }



  render() {
    this.startTimer();
    return(
      <span className={
        this.state.seconds === 0 ? 'timerHidden' : 'timerActive'
      }>
        ({this.state.time.s})
      </span>
    );
  }
}

以及我如何读取它并在父组件中重置它:

import Counter from '../Counter/Counter.js';

export default class Verify extends React.Component {
  state = {
    username: this.username,
    email: this.email,
    code: ""
};
  
constructor(props) {
    super(props);
    this.child = React.createRef();
}

resetTimer = () => {
    this.child.current.startTimer();
};

resendConfirmationCode = async e =>{

    this.resetTimer();
    ...
}

return (

     <button 
         className="btn btn-primary register empty" 
         type="button"
         disabled={this.child.current.seconds > 0} 
         onClick={this.resendConfirmationCode}>Resend code <Counter ref={this.child}/>
     </button>
             
    
);

插入计数器工作正常,也可以重置,但禁用按钮会引发以下错误:

TypeError: Cannot read property 'seconds' of null
Verify.render
> 109 |     disabled={this.child.current.seconds > 0} 

this.child ref 将在初始渲染时 null/undefined。如果计数器组件由于某种原因不可用,您可能还想禁用该按钮,因此您可以只检查 ref 的当前值是假的还是真值以及 state.seconds 的 child大于 0.

<button 
  ...
  disabled={!this.child.current || this.child.current.state.seconds > 0} 
  onClick={this.resendConfirmationCode}
>
  Resend code 
</button>
<Counter ref={this.child} />

如果我们反转第二个条件,我们可以使用可选链接将它们组合成一个比较。

<button 
  ...
  disabled={!this.child.current?.state.seconds <= 0} 
  onClick={this.resendConfirmationCode}
>
  Resend code 
</button>
<Counter ref={this.child} />