无法从道具初始化状态
Can't 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 商店,如果这有什么不同的话。
当我在控制台中打印出 'minutes' 时,我得到了 undefined,并且当它被渲染时果然,我只是在几分钟内得到 NaN。我如何让 props.workPeriod 进入状态以便它被定义并能够被操纵?
我包括了我是如何从 Redux 商店获得 workPeriod 的,以防万一我的问题与此有关,但是 {this.props.workPeriod} 呈现得很好,所以我认为那里一切都很好。
提前致谢!
(经过编辑以纳入之前的建议和问题)
const {minutes, seconds} = this.setState
你的意思是
const {minutes, seconds} = this.state
?
发生这种情况是因为 redux 存储是用一个空对象初始化的。当 redux-form 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;
首先,我知道有很多关于这个主题的问题,我已经通读了所有我认为适用于我的情况的问题。这个线程
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 商店,如果这有什么不同的话。 当我在控制台中打印出 'minutes' 时,我得到了 undefined,并且当它被渲染时果然,我只是在几分钟内得到 NaN。我如何让 props.workPeriod 进入状态以便它被定义并能够被操纵?
我包括了我是如何从 Redux 商店获得 workPeriod 的,以防万一我的问题与此有关,但是 {this.props.workPeriod} 呈现得很好,所以我认为那里一切都很好。
提前致谢!
(经过编辑以纳入之前的建议和问题)
const {minutes, seconds} = this.setState
你的意思是
const {minutes, seconds} = this.state
?
发生这种情况是因为 redux 存储是用一个空对象初始化的。当 redux-form 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;