[英]React: How can this Pomodoro Clock pass the `freecodecamp tests 12 and 13`?
In this React Pomodoro clock, setInterval
calls down
every time state.timeLeftSeconds
is reduced.在这个 React Pomodoro 时钟中,每次
state.timeLeftSeconds
减少时setInterval
调用down
。 However, when attempting to pass the freecodecamp tests 12 and 13, there is a message: Break time didn't start with the correct value.: expected 60 to be at most 5
.但是,当尝试通过 freecodecamp 测试 12 和 13 时,会出现一条消息:
Break time didn't start with the correct value.: expected 60 to be at most 5
。 Yet, when the clock is run the code appears to be working perfectly.然而,当时钟运行时,代码似乎运行良好。 Any help would be greatly appreciated.
任何帮助将不胜感激。 The testing suite is also there in the code sandbox: https://codesandbox.io/s/xenodochial-fog-981wl
测试套件也在代码沙箱中: https : //codesandbox.io/s/xenodochial-fog-981wl
index.js索引.js
import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';
/*
* A simple React component
*/
const initState = {
breakLength: 5,
sessionLength: 25,
init: 'session',
stateIndex: 0,
timeLeft: undefined,
timeLeftSeconds: undefined,
started: false,
intervalFunc: undefined
}
const states = [ { name: 'session', duration: 1500 }, { name: 'break', duration: 300 } ]
const secondsToMins = (time) => {
let converted = ('0' + Math.floor(time / 60)).slice(-2) + ':' + ('0' + Math.floor(time % 60)).slice(-2);
return converted;
}
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = initState;
this.breakDecrement = this.breakDecrement.bind(this);
this.breakIncrement = this.breakIncrement.bind(this);
this.sessionDecrement = this.sessionDecrement.bind(this);
this.sessionIncrement = this.sessionIncrement.bind(this);
this.startStop = this.startStop.bind(this);
this.reset = this.reset.bind(this);
}
componentDidMount() {
let sessionSeconds = this.state.sessionLength * 60;
this.setState({ timeLeftSeconds: sessionSeconds });
this.setState({ timeLeft: secondsToMins(sessionSeconds) });
}
breakDecrement() {
// decrements the breakLength and the breakSeconds
// breakLength is only a number ie. 5 (does not show seconds)
// breakSeconds is that nunber converted into seconds
let breakLength = this.state.breakLength - 1;
if (breakLength > 0 && breakLength < 61){
this.setState({ breakLength: breakLength });
let breakSeconds = breakLength * 60;
states[1]['duration'] = breakSeconds;
}
}
breakIncrement() {
// same as decrement except does increment
let breakLength = this.state.breakLength + 1;
if (breakLength > 0 && breakLength < 61){
this.setState({ breakLength: breakLength });
let breakSeconds = breakLength * 60;
states[1]['duration'] = breakSeconds;
}
}
sessionDecrement() {
// decrements the sessionLength and the sessionSeconds
// sessionLength is only a number ie. 25 (does not show seconds)
// sessionSeconds is that nunber converted into seconds
let sessionLength = this.state.sessionLength - 1;
if (sessionLength > 0 && sessionLength < 61){
states[0]['duration'] = sessionLength*60;
this.setState(prevState => ({
sessionLength: prevState.sessionLength-1,
timeLeftSeconds: (prevState.sessionLength-1)*60,
timeLeft: secondsToMins((prevState.sessionLength-1)*60)})
);
}
}
sessionIncrement() {
// same as decrement except does increment
let sessionLength = this.state.sessionLength + 1;
if (sessionLength > 0 && sessionLength < 61){
states[0]['duration'] = sessionLength*60;
this.setState(prevState => ({
sessionLength: prevState.sessionLength+1,
timeLeftSeconds: (prevState.sessionLength+1)*60,
timeLeft: secondsToMins((prevState.sessionLength+1)*60)})
);
}
}
startStop(id) {
// starts the countDown, which runs continuously until the start/stop button
// is pressed again, which pauses the countdown.
// the id parameter is used by countDown to play the audio beep
if(!this.state.started){
this.countDown(id);
this.setState({ started: true});
}
// pauses the countDown
if(this.state.started){
let intervalFunc = this.state.intervalFunc;
clearInterval(intervalFunc);
this.setState({ started: false});
}
}
reset() {
let intervalFunc = this.state.intervalFunc;
clearInterval(intervalFunc);
// reset state to default values
this.setState({ breakLength: 5 });
this.setState({ sessionLength: 25 });
this.setState({ init: 'session' });
this.setState({ timeLeftSeconds: 1500})
this.setState({ timeLeft: '25:00' });
this.setState({ stateIndex: 0 });
this.setState({ started: false });
this.setState({ intervalFunc: undefined });
}
decreaseCurrentSecond = () => this.state.timeLeftSeconds--;
countDown(id) {
// set the function to a variable and set state to it, so the function
// can be paused with clearInterval()
var intervalFunc = setInterval(
() => down(this.decreaseCurrentSecond()),
1000
);
this.setState({ intervalFunc: intervalFunc });
const down = (time) => {
if (time > 0) {
// converts seconds to MM:SS at every t-minus
this.setState({ timeLeft: secondsToMins(time) });
/*
console.log(time);
console.log(this.state.timeLeft);*/
}
let sound = document.getElementById(id).childNodes[0];
if (time <= 0 ) {
sound.play();
this.setState({ timeLeft: secondsToMins(time) });
console.log(time);
console.log(this.stateIndex);
console.log(this.state.init);
console.log(this.state.timeLeftSeconds);
let stateIndex = (this.state.stateIndex + 1) % states.length;
this.setState({ stateIndex: stateIndex });
this.setState({ init: states[stateIndex]['name'] });
this.setState({ timeLeftSeconds: states[stateIndex]['duration'] });
console.log(time);
console.log(this.stateIndex);
console.log(this.state.init);
console.log(this.state.timeLeftSeconds);
}
};
down(this.decreaseCurrentSecond());
}
render() {
return (
<div id="clock">
<h1 id="title">25-5 Clock</h1>
<div>
<p id="break-label">Break Length</p>
<p id="break-length">{this.state.breakLength}</p>
<button id="break-decrement" onClick={e => this.breakDecrement()}> Decrease </button>
<button id="break-increment" onClick={e => this.breakIncrement()}> Increase </button>
</div>
<div>
<p id="session-label">Session Length</p>
<p id="session-length">{this.state.sessionLength}</p>
<button id="session-decrement" onClick={e => this.sessionDecrement()}> Decrease </button>
<button id="session-increment" onClick={e => this.sessionIncrement()}> Increase </button>
</div>
<hr/>
<div>
<p id="timer-label">{this.state.init}</p>
<p id="time-left">{this.state.timeLeft}</p>
<button id="start_stop" onClick={e => this.startStop(e.target.id)}><audio id="beep" src='./beep.mp3'></audio> start/stop </button>
<button id="reset" onClick={e => this.reset()}> reset </button>
</div>
</div>
);
}
};
/*
* Render the above component into the div#app
*/
ReactDOM.render(<Clock />, document.getElementById("app"));
index.html索引.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>25-5 Clock</title>
<style>
</style>
</head>
<body>
<main>
<div id="app"></app>
</main>
</body>
</html>
The reason those tests are failing is because the timeLeftSeconds
in the state isn't being set properly once the clock goes into the 'break' cycle and vice versa.这些测试失败的原因是因为一旦时钟进入“中断”周期,状态中的
timeLeftSeconds
没有正确设置,反之亦然。 I have made the necessary adjustments below.我在下面做了必要的调整。 Notice the changes in the
decreaseCurrentSecond
and down
methods.注意
decreaseCurrentSecond
和down
方法的变化。
Also, never try to update values in the state directly like you did here - decreaseCurrentSecond = () => this.state.timeLeftSeconds--;
此外,永远不要尝试像您在这里所做的那样直接更新状态中的值 -
decreaseCurrentSecond = () => this.state.timeLeftSeconds--;
. . This is not good practice - Why can't I directly modify a component's state, really?
这不是一个好习惯 - 为什么我不能直接修改组件的状态,真的吗?
import React from "react";
import ReactDOM from "react-dom";
import "./style.css";
/*
* A simple React component
*/
const initState = {
breakLength: 0.5,
sessionLength: 0.5,
init: "session",
// stateIndex: 0,
timeLeft: undefined,
timeLeftSeconds: undefined,
started: false,
intervalFunc: undefined
};
const secondsToMins = (time) => {
let converted =
("0" + Math.floor(time / 60)).slice(-2) +
":" +
("0" + Math.floor(time % 60)).slice(-2);
return converted;
};
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = initState;
this.breakDecrement = this.breakDecrement.bind(this);
this.breakIncrement = this.breakIncrement.bind(this);
this.sessionDecrement = this.sessionDecrement.bind(this);
this.sessionIncrement = this.sessionIncrement.bind(this);
this.startStop = this.startStop.bind(this);
this.reset = this.reset.bind(this);
}
componentDidMount() {
let sessionSeconds = this.state.sessionLength * 60;
this.setState({ timeLeftSeconds: sessionSeconds });
this.setState({ timeLeft: secondsToMins(sessionSeconds) });
}
breakDecrement() {
console.log("break decrement");
// decrements the breakLength and the breakSeconds
// breakLength is only a number ie. 5 (does not show seconds)
// breakSeconds is that nunber converted into seconds
let breakLength = this.state.breakLength - 1;
if (breakLength > 0 && breakLength < 61) {
this.setState({ breakLength: breakLength });
// let breakSeconds = breakLength * 60;
// states[1]["duration"] = breakSeconds;
}
}
breakIncrement() {
// same as decrement except does increment
let breakLength = this.state.breakLength + 1;
if (breakLength > 0 && breakLength < 61) {
this.setState({ breakLength: breakLength });
// let breakSeconds = breakLength * 60;
// states[1]["duration"] = breakSeconds;
}
}
sessionDecrement() {
// decrements the sessionLength and the sessionSeconds
// sessionLength is only a number ie. 25 (does not show seconds)
// sessionSeconds is that nunber converted into seconds
let sessionLength = this.state.sessionLength - 1;
if (sessionLength > 0 && sessionLength < 61) {
// states[0]["duration"] = sessionLength * 60;
this.setState((prevState) => ({
sessionLength: prevState.sessionLength - 1,
timeLeftSeconds: (prevState.sessionLength - 1) * 60,
timeLeft: secondsToMins((prevState.sessionLength - 1) * 60)
}));
}
}
sessionIncrement() {
// same as decrement except does increment
let sessionLength = this.state.sessionLength + 1;
if (sessionLength > 0 && sessionLength < 61) {
// states[0]["duration"] = sessionLength * 60;
this.setState((prevState) => ({
sessionLength: prevState.sessionLength + 1,
timeLeftSeconds: (prevState.sessionLength + 1) * 60,
timeLeft: secondsToMins((prevState.sessionLength + 1) * 60)
}));
}
}
startStop(id) {
// starts the countDown, which runs continuously until the start/stop button
// is pressed again, which pauses the countdown.
// the id parameter is used by countDown to play the audio beep
if (!this.state.started) {
this.setState({ started: true });
this.countDown(id);
}
// pauses the countDown
if (this.state.started) {
this.setState({ started: false });
let intervalFunc = this.state.intervalFunc;
clearInterval(intervalFunc);
}
}
reset() {
let intervalFunc = this.state.intervalFunc;
clearInterval(intervalFunc);
// reset state to default values
this.setState({ breakLength: 5 });
this.setState({ sessionLength: 25 });
this.setState({ init: "session" });
this.setState({ timeLeftSeconds: 1500 });
this.setState({ timeLeft: "25:00" });
// this.setState({ stateIndex: 0 });
this.setState({ started: false });
this.setState({ intervalFunc: undefined });
}
decreaseCurrentSecond = () =>
//this.state.timeLeftSeconds--;
{
this.setState({
timeLeftSeconds: this.state.timeLeftSeconds - 1
});
return this.state.timeLeftSeconds;
};
countDown(id) {
// set the function to a variable and set state to it, so the function
// can be paused with clearInterval()
var intervalFunc = setInterval(
() => down(this.decreaseCurrentSecond()),
1000
);
this.setState({ intervalFunc: intervalFunc });
const down = (time) => {
if (time > 0) {
// converts seconds to MM:SS at every t-minus
this.setState({ timeLeft: secondsToMins(time) });
/*
console.log(time);
console.log(this.state.timeLeft);*/
}
let sound = document.getElementById(id).childNodes[0];
if (time <= 0) {
sound.play();
this.setState({ timeLeft: secondsToMins(time) });
console.log(`##########`);
console.log(time);
// console.log(this.stateIndex);
console.log(this.state.init);
console.log(this.state.timeLeftSeconds);
console.log(`##########`);
// let stateIndex = (this.state.stateIndex + 1) % states.length;
// this.setState({ stateIndex: stateIndex });
this.setState({
init: this.state.init === "session" ? "break" : "session"
});
this.setState({
timeLeftSeconds:
this.state.init === "session"
? this.state.sessionLength * 60 + 1
: this.state.breakLength * 60 + 1
});
console.log(`##########`);
console.log(time);
// console.log(this.stateIndex);
console.log(this.state.init);
console.log(this.state.timeLeftSeconds);
console.log(`##########`);
}
};
// down(this.decreaseCurrentSecond());
}
render() {
return (
<div id="clock">
<h1 id="title">25-5 Clock</h1>
<div>
<p id="break-label">Break Length</p>
<p id="break-length">{this.state.breakLength}</p>
<button id="break-decrement" onClick={(e) => this.breakDecrement()}>
{" "}
Decrease{" "}
</button>
<button id="break-increment" onClick={(e) => this.breakIncrement()}>
{" "}
Increase{" "}
</button>
</div>
<div>
<p id="session-label">Session Length</p>
<p id="session-length">{this.state.sessionLength}</p>
<button
id="session-decrement"
onClick={(e) => this.sessionDecrement()}
>
{" "}
Decrease{" "}
</button>
<button
id="session-increment"
onClick={(e) => this.sessionIncrement()}
>
{" "}
Increase{" "}
</button>
</div>
<hr />
<div>
<p id="timer-label">{this.state.init}</p>
<p id="time-left">{this.state.timeLeft}</p>
<button id="start_stop" onClick={(e) => this.startStop(e.target.id)}>
<audio id="beep" src="./beep.mp3"></audio> start/stop{" "}
</button>
<button id="reset" onClick={(e) => this.reset()}>
{" "}
reset{" "}
</button>
</div>
</div>
);
}
}
/*
* Render the above component into the div#app
*/
ReactDOM.render(<Clock />, document.getElementById("app"));
https://codesandbox.io/s/heuristic-star-i3t8m?file=/src/index.js https://codesandbox.io/s/heuristic-star-i3t8m?file=/src/index.js
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.