无法通过道具初始化状​​态

时间:2020-05-13 23:32:18

标签: reactjs redux redux-form react-props react-state

首先,我知道有关此主题的很多问题,并且我已经阅读了我认为适用于我的情况的所有问题。特别是这个线程React component initialize state from props似乎是我所需要的,但是这里没有提到任何工作。无论如何,到我的代码。这只是一个简单的倒数计时器,以用户输入(以分钟为单位)作为起点:

class Timer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            minutes: props.workPeriod,
            seconds: 0
        };
      }
    componentDidMount() {  
        setInterval(() => {
            const {minutes, seconds} = this.state
            console.log("minute state: ", minutes)
            if(this.props.countdownHasStarted) {
                if(seconds > 0) {
                    this.setState(({seconds}) => ({
                        seconds: seconds - 1
                    }))
                }
                if(seconds === 0) {
                    if(minutes === 0) {
                        clearInterval(this.myInterval)
                    } else {
                        this.setState(({minutes}) => ({
                            minutes: minutes - 1,
                            seconds: 59
                        }))
                    }
                }
            }
        }, 1000)
    }

...

const selector = formValueSelector('intervalSettings')
Timer = connect(state => {
    const workPeriod = selector(state, 'workPeriod')
    return {
        workPeriod,
        countdownHasStarted: state.countdownHasStarted
    }
})(Timer)

由于所有组件都位于组件树上,因此我使用了Redux,因此workPeriod来自Redux存储,如果有什么不同的话。 当我在控制台中打印“分钟”时,我不确定,并且在渲染时确定,我只是得到分钟的NaN。如何使props.workPeriod进入状态,以便对其进行定义并能够对其进行操作?

我介绍了如何从Redux商店获得workPeriod,以防万一我的麻烦与事有关,但是{this.props.workPeriod}效果很好,所以我认为那里一切都很好。

谢谢!

(已编辑,以纳入先前的建议和问题)

2 个答案:

答案 0 :(得分:3)

之所以发生这种情况,是因为redux存储是用空对象初始化的。到redux形式的reducer初始化其自己的initialValues时,<Timer />组件将获得未定义的值workPeriod并启动setInterval()。这是我使用React Hooks解决此问题的方法:

import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { formValueSelector } from "redux-form";

let Timer = ({ workPeriod, countdownHasStarted }) => {
  const [seconds, setSeconds] = useState(0);
  const [minutes, setMinutes] = useState();

  useEffect(() => {
    // first initialize the minutes when the workPeriod is initialized
    setMinutes(workPeriod);
  }, [workPeriod]);

  useEffect(() => {
    let interval;
    if (minutes) {
      interval = setInterval(() => {
        console.log("minute state: ", minutes);
        if (countdownHasStarted) {
          if (seconds > 0) {
            setSeconds((sec) => sec - 1);
          }
          if (seconds === 0) {
            if (minutes === 0) {
              clearInterval(interval);
            } else {
              setMinutes((min) => min - 1);
              setSeconds(59);
            }
          }
        }
      }, 1000);
    }

    return () => {
      // cleanup function
      clearInterval(interval);
    };
  }, [countdownHasStarted, minutes, seconds]);

  return (
    <div className="numbers">
      <div className="box" id="minutes">
        <p>{minutes}</p>
      </div>
      <div className="box" id="colon">
        <p>:</p>
      </div>
      <div className="box" id="seconds">
        <p>{seconds < 10 ? `0${seconds}` : seconds}</p>
      </div>
    </div>
  );
};

Timer = connect((state) => {
  const selector = formValueSelector("intervalSettings");
  const workPeriod = selector(state, "workPeriod");
  return {
    workPeriod,
    countdownHasStarted: state.countdownHasStarted,
  };
})(Timer);

export default Timer;

答案 1 :(得分:1)

const {minutes, seconds} = this.setState

你的意思是

const {minutes, seconds} = this.state