在反应中状态发生变化之前调用 SetState 回调
SetState callback gets called before state is mutated in react
以下是导致我 运行 遇到麻烦的部分的代码分解。
我定义了一个 class 组件来存储状态数据和 "timerState" ,这是本例中的主要焦点,将在 true 和假
this.state={
brkLength:1,
sesnLength:1,
timer:60,
timerState:'false',
timerType:'Session',
}
handleTimer 函数将在 onclick 事件发生后启动。由于 setstate 运行s 是异步的,我不想在状态突变之前调用函数-timeCountDown 和 breakCountDown,我设置它们作为setState的回调函数。
handleTimer(){
console.log(this.state.timerState)
if(this.state.timerType=="Session"){
this.setState({
timerState:!this.state.timerState
},()=>this.timeCountDown())
}else if(this.state.timerType=="Break"){
this.setState({
timerState:!this.state.timerState
},()=>this.breakCountDown())
}
}
然而,正如 console.log 显示在两个地方 - 一个在 handleTimer 中,另一个在 timeCountDown,它们都打印“false”。
timeCountDown(){
console.log(this.state.timerState)
if(this.state.timerState){
this.myCountDown=setInterval(()=>{
if(this.state.timer>0){
this.setState(prevState=>({
timer:prevState.timer-1
}))
}else if(this.state.timer<=0){
clearInterval(this.myCountDown)
this.soundPlay()
this.setState({
timerType:'Break',
timer:this.state.brkLength*60,
},()=>this.breakCountDown())
}
}
,1000)
}else{
clearInterval(this.myCountDown)
}
}
我想知道上面的代码片段出了什么问题。 link 如果您想查看整个编码,请点击此处。
function formatTime(time){
let minutes=Math.floor(time/60)
let seconds=time%60
minutes=minutes<10?"0"+minutes:minutes
seconds=seconds<10?"0"+seconds:seconds
return minutes +":"+seconds
}
const TimerLengthControl=(props)=>(
<div className="LengthContainer">
<div className="controlTitle" id={props.titleID}>{props.title}</div>
<div>
<button
id={props.decrementID}
value="-1"
type={props.type}
onClick={props.onClick}
>
<i className="fas fa-arrow-down"></i>
</button>
<span id={props.spanID}>{props.span}</span>
<button
id={props.incrementID}
value="+1"
type={props.type}
onClick={props.onClick}
>
<i className="fas fa-arrow-up"></i>
</button>
</div>
</div>
)
const TimerControl=(props)=>(
<div className="timerControlContainer">
<div className="timerContainer">
<div id="timer-label">{props.timerType}</div>
<div id="time-left">{formatTime(props.timeLeft)}</div>
</div>
<div className="buttonContainer">
<button id="start_stop" onClick={props.timerHandler}>
<i className="fas fa-play"/>
<i className="fas fa-pause"/>
</button>
<button id="reset">
<i className="fas fa-sync" onClick={props.resetHandler}/>
</button>
</div>
</div>
)
class App extends React.Component{
constructor(){
super()
this.state={
brkLength:1,
sesnLength:1,
timer:60,
timerState:'false',
timerType:'Session',
}
this.handleReset=this.handleReset.bind(this)
this.handleOperation=this.handleOperation.bind(this)
this.handleBreakLength=this.handleBreakLength.bind(this)
this.handleSessionLength=this.handleSessionLength.bind(this)
this.handleTimer=this.handleTimer.bind(this)
};
handleReset(){
clearInterval(this.myCountDown)
this.setState({
brkLength:5,
sesnLength:25,
timer:1500,
timerState:'false',
timerType:'Session',
})
}
timeCountDown(){
console.log(this.state.timerState)
if(this.state.timerState){
this.myCountDown=setInterval(()=>{
if(this.state.timer>0){
this.setState(prevState=>({
timer:prevState.timer-1
}))
}else if(this.state.timer<=0){
clearInterval(this.myCountDown)
this.soundPlay()
this.setState({
timerType:'Break',
timer:this.state.brkLength*60,
},()=>this.breakCountDown())
}
}
,1000)
}else{
clearInterval(this.myCountDown)
}
}
soundPlay(){
const audio= new Audio("https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav")
audio.play()
}
breakCountDown(){
if(this.state.timerState){
this.myCountDown=setInterval(()=>{
if(this.state.timer>0){
this.setState({timer:this.state.timer-1})
}else if(this.state.timer<=0){
clearInterval(this.myCountDown)
this.soundPlay()
this.setState({
timerType:'Session',
timer:this.state.sesnLength*60
})
}
},1000)
}else{
clearInterval(this.myCountDown)
}
}
handleTimer(){
console.log(this.state.timerState)
if(this.state.timerType=="Session"){
this.setState({
timerState:!this.state.timerState
},()=>this.timeCountDown())
}else if(this.state.timerType=="Break"){
this.setState({
timerState:!this.state.timerState
},()=>this.breakCountDown())
}
}
handleOperation(stateToChange,amount){
const breakLength=this.state.brkLength
const sessionLength=this.state.sesnLength
if(stateToChange=="sesnLength"&&sessionLength==1&&amount<0){
return
}else if(stateToChange=="sesnLength"&&sessionLength==60&&amount>0){
return
}else if(stateToChange=="sesnLength"){
this.setState({
[stateToChange]:this.state[stateToChange]+Number(amount)*1,
timer:this.state.timer+Number(amount)*60
})
}
if(stateToChange=="brkLength"&&breakLength==1&&amount<0){
return
}else if (stateToChange=="brkLength"){
this.setState({[stateToChange]:this.state[stateToChange]+Number(amount)})
}
}
handleBreakLength(e){
const {value}=e.currentTarget
const type="brkLength"
this.handleOperation(type,value)
}
handleSessionLength(e){
const {value}=e.currentTarget
const type="sesnLength"
this.handleOperation(type,value)
}
render(){
return(
<div>
<TimerLengthControl
title="Break Length"
titleID="break-label"
decrementID="break-decrement"
incrementID="break-increment"
spanID="break-length"
span={this.state.brkLength}
onClick={this.handleBreakLength}
/>
<TimerLengthControl
title="Session Length"
titleID="session-label"
decrementID="session-decrement"
incrementID="session-increment"
spanID="session-length"
span={this.state.sesnLength}
onClick={this.handleSessionLength}
/>
<TimerControl
timeLeft={this.state.timer}
resetHandler={this.handleReset}
timerHandler={this.handleTimer}
timerType={this.state.timerType}
/>
</div>
);
}
}
ReactDOM.render(<App />,document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
</head>
<body>
<div id="root">
</div>
</body>
</html>
这个方法对你有帮助吗?
this.setState((preVState)
timerState:!preVState.timerState
},()=>this.timeCountDown())
您想在以后的更新中使用当前状态值。最可靠的方法是传递一个函数。这将始终具有正确的值。
问题是您使用 'false'
而不是 false
作为 timerState
的“关闭”值:
this.setState({
brkLength: 5,
sesnLength: 25,
timer: 1500,
timerState: 'false', // <==== here
timerType: 'Session',
});
那是 字符串 ,不是布尔值。因为它是一个非空字符串,所以它是真实的。所以
if (this.state.timerState) {
...当 timerState
为 'false'
时分支到 if
块
稍后,当你这样做时
this.setState({
timerState: !this.state.timerState
}, () => this.timeCountDown());
...它将 'false'
(字符串)更改为 false
(布尔值)。
布尔值不放在引号中:
this.setState({
brkLength: 5,
sesnLength: 25,
timer: 1500,
timerState: false, // <====
timerType: 'Session',
});
已更新:
function formatTime(time) {
let minutes = Math.floor(time / 60);
let seconds = time % 60;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
return minutes + ":" + seconds;
}
const TimerLengthControl = (props) => (
<div className="LengthContainer">
<div className="controlTitle" id={props.titleID}>{props.title}</div>
<div>
<button
id={props.decrementID}
value="-1"
type={props.type}
onClick={props.onClick}
>
<i className="fas fa-arrow-down"></i>
</button>
<span id={props.spanID}>{props.span}</span>
<button
id={props.incrementID}
value="+1"
type={props.type}
onClick={props.onClick}
>
<i className="fas fa-arrow-up"></i>
</button>
</div>
</div>
);
const TimerControl = (props) => (
<div className="timerControlContainer">
<div className="timerContainer">
<div id="timer-label">{props.timerType}</div>
<div id="time-left">{formatTime(props.timeLeft)}</div>
</div>
<div className="buttonContainer">
<button id="start_stop" onClick={props.timerHandler}>
<i className="fas fa-play" />
<i className="fas fa-pause" />
</button>
<button id="reset">
<i className="fas fa-sync" onClick={props.resetHandler} />
</button>
</div>
</div>
);
class App extends React.Component {
constructor() {
super();
this.state = {
brkLength: 1,
sesnLength: 1,
timer: 60,
timerState: false, // <==== here
timerType: 'Session',
};
this.handleReset = this.handleReset.bind(this);
this.handleOperation = this.handleOperation.bind(this);
this.handleBreakLength = this.handleBreakLength.bind(this);
this.handleSessionLength = this.handleSessionLength.bind(this);
this.handleTimer = this.handleTimer.bind(this);
};
handleReset() {
clearInterval(this.myCountDown);
this.setState({
brkLength: 5,
sesnLength: 25,
timer: 1500,
timerState: false, // <==== here
timerType: 'Session',
});
}
timeCountDown() {
console.log(1, this.state.timerState);
if (this.state.timerState) {
this.myCountDown = setInterval(() => {
if (this.state.timer > 0) {
this.setState(prevState => ({
timer: prevState.timer - 1
}));
} else if (this.state.timer <= 0) {
clearInterval(this.myCountDown);
this.soundPlay();
this.setState({
timerType: 'Break',
timer: this.state.brkLength * 60,
}, () => this.breakCountDown());
}
}
, 1000);
} else {
clearInterval(this.myCountDown);
}
}
soundPlay() {
const audio = new Audio("https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav");
audio.play();
}
breakCountDown() {
if (this.state.timerState) {
this.myCountDown = setInterval(() => {
if (this.state.timer > 0) {
this.setState({ timer: this.state.timer - 1 });
} else if (this.state.timer <= 0) {
clearInterval(this.myCountDown);
this.soundPlay();
this.setState({
timerType: 'Session',
timer: this.state.sesnLength * 60
});
}
}, 1000);
} else {
clearInterval(this.myCountDown);
}
}
handleTimer() {
console.log(2, this.state.timerState);
if (this.state.timerType == "Session") {
this.setState({
timerState: !this.state.timerState
}, () => this.timeCountDown());
} else if (this.state.timerType == "Break") {
this.setState({
timerState: !this.state.timerState
}, () => this.breakCountDown());
}
}
handleOperation(stateToChange, amount) {
const breakLength = this.state.brkLength;
const sessionLength = this.state.sesnLength;
if (stateToChange == "sesnLength" && sessionLength == 1 && amount < 0) {
return;
} else if (stateToChange == "sesnLength" && sessionLength == 60 && amount > 0) {
return;
} else if (stateToChange == "sesnLength") {
this.setState({
[stateToChange]: this.state[stateToChange] + Number(amount) * 1,
timer: this.state.timer + Number(amount) * 60
});
}
if (stateToChange == "brkLength" && breakLength == 1 && amount < 0) {
return;
} else if (stateToChange == "brkLength") {
this.setState({ [stateToChange]: this.state[stateToChange] + Number(amount) });
}
}
handleBreakLength(e) {
const { value } = e.currentTarget;
const type = "brkLength";
this.handleOperation(type, value);
}
handleSessionLength(e) {
const { value } = e.currentTarget;
const type = "sesnLength";
this.handleOperation(type, value);
}
render() {
return (
<div>
<TimerLengthControl
title="Break Length"
titleID="break-label"
decrementID="break-decrement"
incrementID="break-increment"
spanID="break-length"
span={this.state.brkLength}
onClick={this.handleBreakLength}
/>
<TimerLengthControl
title="Session Length"
titleID="session-label"
decrementID="session-decrement"
incrementID="session-increment"
spanID="session-length"
span={this.state.sesnLength}
onClick={this.handleSessionLength}
/>
<TimerControl
timeLeft={this.state.timer}
resetHandler={this.handleReset}
timerHandler={this.handleTimer}
timerType={this.state.timerType}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
</head>
<body>
<div id="root">
</div>
</body>
</html>
此外,正如我在评论中所说,当基于现有状态更新状态时,通常您希望使用回调形式。所以代替:
this.setState({
timerState: !this.state.timerState
}, () => this.timeCountDown());
做
this.setState(
({timerState}) => ({timerState: !timerState}),
() => this.timeCountDown()
);
以下是导致我 运行 遇到麻烦的部分的代码分解。
我定义了一个 class 组件来存储状态数据和 "timerState" ,这是本例中的主要焦点,将在 true 和假
this.state={
brkLength:1,
sesnLength:1,
timer:60,
timerState:'false',
timerType:'Session',
}
handleTimer 函数将在 onclick 事件发生后启动。由于 setstate 运行s 是异步的,我不想在状态突变之前调用函数-timeCountDown 和 breakCountDown,我设置它们作为setState的回调函数。
handleTimer(){
console.log(this.state.timerState)
if(this.state.timerType=="Session"){
this.setState({
timerState:!this.state.timerState
},()=>this.timeCountDown())
}else if(this.state.timerType=="Break"){
this.setState({
timerState:!this.state.timerState
},()=>this.breakCountDown())
}
}
然而,正如 console.log 显示在两个地方 - 一个在 handleTimer 中,另一个在 timeCountDown,它们都打印“false”。
timeCountDown(){
console.log(this.state.timerState)
if(this.state.timerState){
this.myCountDown=setInterval(()=>{
if(this.state.timer>0){
this.setState(prevState=>({
timer:prevState.timer-1
}))
}else if(this.state.timer<=0){
clearInterval(this.myCountDown)
this.soundPlay()
this.setState({
timerType:'Break',
timer:this.state.brkLength*60,
},()=>this.breakCountDown())
}
}
,1000)
}else{
clearInterval(this.myCountDown)
}
}
我想知道上面的代码片段出了什么问题。 link 如果您想查看整个编码,请点击此处。
function formatTime(time){
let minutes=Math.floor(time/60)
let seconds=time%60
minutes=minutes<10?"0"+minutes:minutes
seconds=seconds<10?"0"+seconds:seconds
return minutes +":"+seconds
}
const TimerLengthControl=(props)=>(
<div className="LengthContainer">
<div className="controlTitle" id={props.titleID}>{props.title}</div>
<div>
<button
id={props.decrementID}
value="-1"
type={props.type}
onClick={props.onClick}
>
<i className="fas fa-arrow-down"></i>
</button>
<span id={props.spanID}>{props.span}</span>
<button
id={props.incrementID}
value="+1"
type={props.type}
onClick={props.onClick}
>
<i className="fas fa-arrow-up"></i>
</button>
</div>
</div>
)
const TimerControl=(props)=>(
<div className="timerControlContainer">
<div className="timerContainer">
<div id="timer-label">{props.timerType}</div>
<div id="time-left">{formatTime(props.timeLeft)}</div>
</div>
<div className="buttonContainer">
<button id="start_stop" onClick={props.timerHandler}>
<i className="fas fa-play"/>
<i className="fas fa-pause"/>
</button>
<button id="reset">
<i className="fas fa-sync" onClick={props.resetHandler}/>
</button>
</div>
</div>
)
class App extends React.Component{
constructor(){
super()
this.state={
brkLength:1,
sesnLength:1,
timer:60,
timerState:'false',
timerType:'Session',
}
this.handleReset=this.handleReset.bind(this)
this.handleOperation=this.handleOperation.bind(this)
this.handleBreakLength=this.handleBreakLength.bind(this)
this.handleSessionLength=this.handleSessionLength.bind(this)
this.handleTimer=this.handleTimer.bind(this)
};
handleReset(){
clearInterval(this.myCountDown)
this.setState({
brkLength:5,
sesnLength:25,
timer:1500,
timerState:'false',
timerType:'Session',
})
}
timeCountDown(){
console.log(this.state.timerState)
if(this.state.timerState){
this.myCountDown=setInterval(()=>{
if(this.state.timer>0){
this.setState(prevState=>({
timer:prevState.timer-1
}))
}else if(this.state.timer<=0){
clearInterval(this.myCountDown)
this.soundPlay()
this.setState({
timerType:'Break',
timer:this.state.brkLength*60,
},()=>this.breakCountDown())
}
}
,1000)
}else{
clearInterval(this.myCountDown)
}
}
soundPlay(){
const audio= new Audio("https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav")
audio.play()
}
breakCountDown(){
if(this.state.timerState){
this.myCountDown=setInterval(()=>{
if(this.state.timer>0){
this.setState({timer:this.state.timer-1})
}else if(this.state.timer<=0){
clearInterval(this.myCountDown)
this.soundPlay()
this.setState({
timerType:'Session',
timer:this.state.sesnLength*60
})
}
},1000)
}else{
clearInterval(this.myCountDown)
}
}
handleTimer(){
console.log(this.state.timerState)
if(this.state.timerType=="Session"){
this.setState({
timerState:!this.state.timerState
},()=>this.timeCountDown())
}else if(this.state.timerType=="Break"){
this.setState({
timerState:!this.state.timerState
},()=>this.breakCountDown())
}
}
handleOperation(stateToChange,amount){
const breakLength=this.state.brkLength
const sessionLength=this.state.sesnLength
if(stateToChange=="sesnLength"&&sessionLength==1&&amount<0){
return
}else if(stateToChange=="sesnLength"&&sessionLength==60&&amount>0){
return
}else if(stateToChange=="sesnLength"){
this.setState({
[stateToChange]:this.state[stateToChange]+Number(amount)*1,
timer:this.state.timer+Number(amount)*60
})
}
if(stateToChange=="brkLength"&&breakLength==1&&amount<0){
return
}else if (stateToChange=="brkLength"){
this.setState({[stateToChange]:this.state[stateToChange]+Number(amount)})
}
}
handleBreakLength(e){
const {value}=e.currentTarget
const type="brkLength"
this.handleOperation(type,value)
}
handleSessionLength(e){
const {value}=e.currentTarget
const type="sesnLength"
this.handleOperation(type,value)
}
render(){
return(
<div>
<TimerLengthControl
title="Break Length"
titleID="break-label"
decrementID="break-decrement"
incrementID="break-increment"
spanID="break-length"
span={this.state.brkLength}
onClick={this.handleBreakLength}
/>
<TimerLengthControl
title="Session Length"
titleID="session-label"
decrementID="session-decrement"
incrementID="session-increment"
spanID="session-length"
span={this.state.sesnLength}
onClick={this.handleSessionLength}
/>
<TimerControl
timeLeft={this.state.timer}
resetHandler={this.handleReset}
timerHandler={this.handleTimer}
timerType={this.state.timerType}
/>
</div>
);
}
}
ReactDOM.render(<App />,document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
</head>
<body>
<div id="root">
</div>
</body>
</html>
这个方法对你有帮助吗?
this.setState((preVState)
timerState:!preVState.timerState
},()=>this.timeCountDown())
您想在以后的更新中使用当前状态值。最可靠的方法是传递一个函数。这将始终具有正确的值。
问题是您使用 'false'
而不是 false
作为 timerState
的“关闭”值:
this.setState({
brkLength: 5,
sesnLength: 25,
timer: 1500,
timerState: 'false', // <==== here
timerType: 'Session',
});
那是 字符串 ,不是布尔值。因为它是一个非空字符串,所以它是真实的。所以
if (this.state.timerState) {
...当 timerState
为 'false'
if
块
稍后,当你这样做时
this.setState({
timerState: !this.state.timerState
}, () => this.timeCountDown());
...它将 'false'
(字符串)更改为 false
(布尔值)。
布尔值不放在引号中:
this.setState({
brkLength: 5,
sesnLength: 25,
timer: 1500,
timerState: false, // <====
timerType: 'Session',
});
已更新:
function formatTime(time) {
let minutes = Math.floor(time / 60);
let seconds = time % 60;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
return minutes + ":" + seconds;
}
const TimerLengthControl = (props) => (
<div className="LengthContainer">
<div className="controlTitle" id={props.titleID}>{props.title}</div>
<div>
<button
id={props.decrementID}
value="-1"
type={props.type}
onClick={props.onClick}
>
<i className="fas fa-arrow-down"></i>
</button>
<span id={props.spanID}>{props.span}</span>
<button
id={props.incrementID}
value="+1"
type={props.type}
onClick={props.onClick}
>
<i className="fas fa-arrow-up"></i>
</button>
</div>
</div>
);
const TimerControl = (props) => (
<div className="timerControlContainer">
<div className="timerContainer">
<div id="timer-label">{props.timerType}</div>
<div id="time-left">{formatTime(props.timeLeft)}</div>
</div>
<div className="buttonContainer">
<button id="start_stop" onClick={props.timerHandler}>
<i className="fas fa-play" />
<i className="fas fa-pause" />
</button>
<button id="reset">
<i className="fas fa-sync" onClick={props.resetHandler} />
</button>
</div>
</div>
);
class App extends React.Component {
constructor() {
super();
this.state = {
brkLength: 1,
sesnLength: 1,
timer: 60,
timerState: false, // <==== here
timerType: 'Session',
};
this.handleReset = this.handleReset.bind(this);
this.handleOperation = this.handleOperation.bind(this);
this.handleBreakLength = this.handleBreakLength.bind(this);
this.handleSessionLength = this.handleSessionLength.bind(this);
this.handleTimer = this.handleTimer.bind(this);
};
handleReset() {
clearInterval(this.myCountDown);
this.setState({
brkLength: 5,
sesnLength: 25,
timer: 1500,
timerState: false, // <==== here
timerType: 'Session',
});
}
timeCountDown() {
console.log(1, this.state.timerState);
if (this.state.timerState) {
this.myCountDown = setInterval(() => {
if (this.state.timer > 0) {
this.setState(prevState => ({
timer: prevState.timer - 1
}));
} else if (this.state.timer <= 0) {
clearInterval(this.myCountDown);
this.soundPlay();
this.setState({
timerType: 'Break',
timer: this.state.brkLength * 60,
}, () => this.breakCountDown());
}
}
, 1000);
} else {
clearInterval(this.myCountDown);
}
}
soundPlay() {
const audio = new Audio("https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav");
audio.play();
}
breakCountDown() {
if (this.state.timerState) {
this.myCountDown = setInterval(() => {
if (this.state.timer > 0) {
this.setState({ timer: this.state.timer - 1 });
} else if (this.state.timer <= 0) {
clearInterval(this.myCountDown);
this.soundPlay();
this.setState({
timerType: 'Session',
timer: this.state.sesnLength * 60
});
}
}, 1000);
} else {
clearInterval(this.myCountDown);
}
}
handleTimer() {
console.log(2, this.state.timerState);
if (this.state.timerType == "Session") {
this.setState({
timerState: !this.state.timerState
}, () => this.timeCountDown());
} else if (this.state.timerType == "Break") {
this.setState({
timerState: !this.state.timerState
}, () => this.breakCountDown());
}
}
handleOperation(stateToChange, amount) {
const breakLength = this.state.brkLength;
const sessionLength = this.state.sesnLength;
if (stateToChange == "sesnLength" && sessionLength == 1 && amount < 0) {
return;
} else if (stateToChange == "sesnLength" && sessionLength == 60 && amount > 0) {
return;
} else if (stateToChange == "sesnLength") {
this.setState({
[stateToChange]: this.state[stateToChange] + Number(amount) * 1,
timer: this.state.timer + Number(amount) * 60
});
}
if (stateToChange == "brkLength" && breakLength == 1 && amount < 0) {
return;
} else if (stateToChange == "brkLength") {
this.setState({ [stateToChange]: this.state[stateToChange] + Number(amount) });
}
}
handleBreakLength(e) {
const { value } = e.currentTarget;
const type = "brkLength";
this.handleOperation(type, value);
}
handleSessionLength(e) {
const { value } = e.currentTarget;
const type = "sesnLength";
this.handleOperation(type, value);
}
render() {
return (
<div>
<TimerLengthControl
title="Break Length"
titleID="break-label"
decrementID="break-decrement"
incrementID="break-increment"
spanID="break-length"
span={this.state.brkLength}
onClick={this.handleBreakLength}
/>
<TimerLengthControl
title="Session Length"
titleID="session-label"
decrementID="session-decrement"
incrementID="session-increment"
spanID="session-length"
span={this.state.sesnLength}
onClick={this.handleSessionLength}
/>
<TimerControl
timeLeft={this.state.timer}
resetHandler={this.handleReset}
timerHandler={this.handleTimer}
timerType={this.state.timerType}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
</head>
<body>
<div id="root">
</div>
</body>
</html>
此外,正如我在评论中所说,当基于现有状态更新状态时,通常您希望使用回调形式。所以代替:
this.setState({
timerState: !this.state.timerState
}, () => this.timeCountDown());
做
this.setState(
({timerState}) => ({timerState: !timerState}),
() => this.timeCountDown()
);