我正在做FCC锻炼Pomodoro Clock这样的工作。我认为这是一个问题,当倒数计时在最后一分钟时,暂停将不起作用。顺便说一句,暂停可以在最后一分钟生效。我怀疑此问题会导致其他测试失败。还要测试说重置功能不起作用,但可以起作用。
编辑: 我的问题的更深层解释: 方法 paused()用于将状态 paused 从 false 更改为 true ,反之亦然。该方法在 timer()方法内调用,该方法的作用还在于启动 setInterval 。在变量 this.clearTimer 中设置了 setInterval 。如果已暂停为true,则会启动 clearInterval()并停止计时器。
点击具有 start_stop id 的元素,已暂停进行更改,就会进行评估,就像我之前所说的那样;假=> setInterval去; true => setInterval停止。
未暂停时,从状态记录的值中设置setInterval。问题是,当您暂停计时器的时间少于一分钟(59、58等)时,即使暂停状态从“真”更改为“假”,它也不会恢复倒计时?如果倒数计时超过1分钟,则开始/暂停会按规定进行。
您可以在以下位置查看代码:my pen
这是主要组件的代码(来自本地):
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.css';
import './style.scss';
import Item from "./item.js";
import Arrow from "./arrow.js";
import Fa from "./fa.js";
class Pomodoro extends React.Component {
constructor(props) {
super(props);
this.state = {
breakLength: 5,
multiplier: 25,
base: 1000,
time: 0,
minutes: 25,
seconds: 60,
paused: false,
session: false,
break: true,
disabled: false,
};
this.increment = this.increment.bind(this);
this.decrement = this.decrement.bind(this);
this.timer = this.timer.bind(this);
this.reset = this.reset.bind(this);
this.paused = this.paused.bind(this);
this.myRef = React.createRef();
this.clearTimer = null;
}
componentDidMount(){
this.setState({
time: ""+(this.state.multiplier*this.state.base*60),
minutes: this.state.multiplier,
seconds: this.state.seconds === 60 ? "00" : this.state.seconds ,
});
}
paused(){
this.setState({
paused: !this.state.paused
});
}
timer(){
this.paused();
if(this.state.paused === false){
if((this.state.minutes!==0 && this.state.seconds!==0) || (this.state.seconds!==0)){
this.clearTimer = setInterval(() => {
if(this.state.session===false){
console.log("Sada ide session.");
this.setState({
time: ""+(this.state.time-this.state.base),
minutes: this.state.minutes > 0 ? Math.floor(((this.state.time-this.state.base)/(this.state.base))/60) : this.state.minutes,
seconds: this.state.seconds > 0 ? this.state.seconds-1 : 59,
session: (this.state.minutes===0 && this.state.seconds===1) ? true : false,
break: (this.state.minutes===0 && this.state.seconds===1) ? false : true,
});
}
if(this.state.break===false && this.state.session===true && this.state.time==="0"){
console.log("Kraj session-a. Sada ide resetovanje, pa break.");
this.setState({
time: ""+(this.state.breakLength*this.state.base*60),
minutes: this.state.breakLength,
seconds: 60,
});
}
if(this.state.break===false){
console.log("Sada ide break.");
this.setState({
time: ""+(this.state.time-this.state.base),
minutes: this.state.minutes > 0 ? Math.floor(((this.state.time-this.state.base)/(this.state.base))/60) : this.state.minutes,
seconds: this.state.seconds > 0 ? this.state.seconds-1 : 59,
session: (this.state.minutes===0 && this.state.seconds===1) ? false : true,
break: (this.state.minutes===0 && this.state.seconds===1) ? true : false,
});
}
if(this.state.break===true && this.state.session===false && this.state.time==="0"){
console.log("Kraj break-a. Sada ide resetovanje, pa session.");
this.setState({
time: ""+(this.state.multiplier*this.state.base*60),
minutes: this.state.multiplier,
seconds: this.state.seconds === 60 ? "00" : this.state.seconds,
});
}
}, this.state.base);
}
}
else{
clearInterval(this.clearTimer);
}
}
reset(){
this.myRef.current.pause();
this.myRef.current.currentTime = 0;
clearInterval(this.clearTimer);
this.clearTimer = null;
this.setState({
breakLength: 5,
multiplier: 25,
base: 1000,
time: ""+(25*1000*60),
minutes: 25,
seconds: 60,
paused: false,
session: false,
break: true,
disabled: false,
});
}
increment(e){
console.log(e.target.id);
let myId = e.target.id;
if(myId==="break-increment"){
this.setState({
breakLength: this.state.breakLength <60 ? this.state.breakLength+1 : this.state.breakLength,
});
}
else if(myId==="session-increment"){
this.setState({
multiplier: this.state.multiplier < 60 ? this.state.multiplier+1 : this.state.multiplier,
time: this.state.time !== "60" ? ""+((this.state.multiplier+1)*this.state.base*60) : this.state.time,
minutes: this.state.minutes < 60 ? this.state.multiplier+1 : this.state.minutes,
});
}
}
decrement(e){
console.log(e.target.id);
let myId = e.target.id;
if(myId==="break-decrement" && this.state.breakLength > 1){
this.setState({
breakLength: this.state.breakLength > 1 ? this.state.breakLength-1 : this.state.breakLength,
});
}
else if(myId==="session-decrement" && this.state.multiplier > 1 && this.state.time > 1 && this.state.minutes > 1){
this.setState({
multiplier: this.state.multiplier > 1 ? this.state.multiplier-1 : this.state.multiplier,
time: this.state.time > 1 ? (""+((this.state.multiplier-1)*this.state.base*60)) : this.state.time,
minutes: this.state.minutes > 1 ? this.state.multiplier-1: this.state.minutes,
});
}
}
render(){
//console.log(this.state);
const minutes = (""+this.state.minutes).length===1 ? "0"+this.state.minutes : this.state.minutes;
const seconds = this.state.seconds===60 ? "00" : ((""+this.state.seconds).length===1 ? "0"+this.state.seconds : this.state.seconds);
const time = minutes+":"+seconds;
if(time==="00:00"){
console.log("1: "+time);
console.log("2: "+this.state.minutes+":"+this.state.seconds);
this.myRef.current.play();
}
/*if((this.state.minutes+":"+this.state.seconds)===time){
alert("alert2: "+this.state.minutes+":"+this.state.seconds);
}*/
const lastSesMin = (minutes==="00") ? {color: 'red',} : {};
const decrement = this.clearTimer ? ()=>{} : this.decrement;
const increment = this.clearTimer ? ()=>{} : this.increment;
const item2Head = <h3 id="break-label">Break Length</h3>;
const fa1 = <Fa klasa={"fa fa-arrow-down fa-2x"} id={"break-decrement"} onClick={decrement}/>;
const fa2 = <Fa klasa={"fa fa-arrow-up fa-2x"} id={"break-increment"} onClick={increment}/>;
const arr1 = [<Arrow klasa={"arrow"} key={0} arrow={item2Head}/>, <br key={1}/>, <Arrow klasa={"arrow"} key={2} arrow={fa1}/>, <Arrow id={"break-length"} klasa={"nums"} key={3} arrow={this.state.breakLength}/> , <Arrow key={4} klasa={"arrow"} arrow={fa2}/>];
const item3Head = <h3 id="session-label">Session Length</h3>;
const fa3 = <Fa klasa={"fa fa-arrow-down fa-2x"} id={"session-decrement"} onClick={decrement}/>;
const fa4 = <Fa klasa={"fa fa-arrow-up fa-2x"} id={"session-increment"} onClick={increment}/>;
const arr2 = [<Arrow klasa={"arrow"} key={0} arrow={item3Head}/>, <br key={1}/>, <Arrow klasa={"arrow"} key={2} arrow={fa3}/>, <Arrow klasa={"nums"} id={"session-length"} key={3} arrow={this.state.multiplier}/> , <Arrow key={4} klasa={"arrow"} arrow={fa4}/>];
const countdownLabel = (this.state.session===false && this.state.break===true) ? "Session" : "Break";
const item4Head = <h3 key={0} id={"timer-label"} style={lastSesMin}>{countdownLabel}</h3>;
const nums2 = <div key={1} className="nums" style={lastSesMin} id={"time-left"}>{time}</div>;
const arr3 = [item4Head, nums2];
const fa5 = <Fa key={0} klasa={"fa fa-play arrow controls"} title={"start-pause"}/>;
const fa6 = <Fa key={1} klasa={"fa fa-pause arrow controls"} title={"start-pause"}/>;
const fa7 = <Fa key={2} klasa={"fa fa-refresh arrow controls"} id="reset" title={"reset"} onClick={this.reset}/>;
const startPause = <div id="start_stop" key={4} onClick={this.timer}>{fa5}{fa6}</div>;
const arr4 = [startPause, fa7];
return(
<div className="grid-container cent">
<Item klasa={"item1"} arrowsAndNums={"Pomodoro Clock"}/>
<Item klasa={"item2"} arrowsAndNums={arr1}/>
<Item klasa={"item3"} arrowsAndNums={arr2}/>
<Item klasa={"item4"} arrowsAndNums={arr3}/>
<Item klasa={"item4"} arrowsAndNums={arr4}/>
<audio ref={this.myRef} id="beep" src="http://soundbible.com/grab.php?id=2158&type=wav"></audio>
</div>
);
}
}
ReactDOM.render(<Pomodoro/>, document.getElementById('root'));
Edit2:
我解决了暂停问题。我刚刚将行if(this.state.minutes!==0 && this.state.seconds!==0){
更改为行if((this.state.minutes!==0 && this.state.seconds!==0) || (this.state.seconds!==0)){
。
有些图像即使没有错误也显示测试错误。 PS:为了对练习进行错误测试,已使用fcc的错误测试脚本来生成这些假定的错误。
编辑4: 正如我最近发现的那样,甚至FCC的番茄酱有时也无法通过测试。有时在不同的浏览器中,有时在星期日,有时等。 长话短说,我设计了新代码,解决了以前所做的编辑中的问题。但是,它仍然遭受与上述FCC番茄番茄相同的问题。我在某处读到一些有关定时事件的信息,定时事件的实现和执行取决于浏览器,在这种情况下,测试套件本身也是如此,我的pomodoro也是如此。因此应该存在各种“冲突” ...解决这些不一致和冲突,以便在每个浏览器中的每项诉讼/测试中,看起来都是无法克服的,我想会...我想问的是,可以吗?如果我提交我的番茄,关于所说的一切? 我的改进pomodoro 添加了注释,这些注释解释了代码的功能,因此可以随意浏览。 我的测试图片未通过: 在左上方,您可以看到28/29通过的测试。 注意::您可以在Codepen中看到更新的代码以及注释。
答案 0 :(得分:1)
只需阅读一些代码(无需测试您的沙盒),但是我发现一个问题,由于可能的竞争条件,该问题可能导致一些难以理解的错误:
paused(){
this.setState({
paused: !this.state.paused
});
}
timer(){
this.paused();
if(this.state.paused === false){
// ...
timer()
正在调用paused
,状态在此更新。然后timer()
检查新状态。
问题:
setState
may be batched,因此对paused
的连续调用可能基于某个值。解决方案:使用功能作为状态更新程序:
setState(prevState => ({
paused: !prevState.paused
}));
setState
may be asynchronous(相同链接),因此当在paused
中读取时,timer()
的状态可能无法反映该更改!解决方案:将回调用作setState()
的第二个参数:
setState(prevState => ({
paused: !prevState.paused
}), () => {
// You can read updated this.state.paused here....
});
因此整个代码片段可以这样实现:
paused(callback){
setState(prevState => ({
paused: !prevState.paused
}), callback);
}
timer(){
this.paused(() => {
// if(this.state.paused === false){
// ...
});
但是,如果您有很多这样的地方,则可以快速进入某种回调地狱。并且,与这些状态变化并行地管理计时器的启动/停止可能变得非常棘手。您至少可以简化计时器,但让其始终运行(从componentDidMount()
开始,在componentWillUnmount()
停止),并决定每个滴答应做什么(例如,在“暂停”时什么也不做,或者让“暂停”指示灯闪烁...)
侧面说明:像base
这样的变量不需要处于状态,因为它们只是内部变量,不需要触发组件的重新呈现。