Stop countdown time - javascript

constructor(props) {
super(props);
this.state = {
count: 20
};
}
const {count} = this.state
componentDidMount (){
const {startCount} = this.props
this.setState({
count: startCount
})
this.doIntervalChange()
}
componentDidMount (){
this.myInterval = setInterval(() => {
this.setState(prevState => ({
count: prevState.count - 1
}))
},1000)
}
componentWillMount (){
clearInterval(this.myInterval)
}

Try this (untested):
this.myInterval = setInterval(() => {
this.setState(prevState => {
const newCount = prevState.count - 1;
if (newCount == 0) {
clearInterval(this.myInterval);
}
return { count: newCount };
});
}, 1000);

constructor (props){
super(props)
this.state = {
count: 20
}
}
render() {
const {count} = this.state
return (
<div>
<Container className="comming">
<Form className="boxrandomtest">
<h1 className="textrandomtest">แบบทดสอบวัดระดับ</h1> <h1 className="cdtimer"><FontAwesomeIcon icon="clock" /> {count}</h1>
<Form className="Q1">
<h3>1. เวลาใดที่กินเวลาน้อยที่สุด</h3> <br></br>
<Button className="rdTest1" href='/randomtest2'><h5>ก.อดีต</h5></Button><br></br>
<Button className="rdTest1" href='/randomtest13'><h5>ข.ปัจจุบัน</h5></Button><br></br>
<Button className="rdTest1" href='/randomtest2'><h5>ค.อนาคต</h5></Button><br></br>
</Form>
<Button className="rdTestbt1" href='/randomtest1'><h5>รีหน้าเดิม</h5></Button>
<Button className="rdTestbt2" href='/randomtest2'><h5>ข้อต่อไป</h5></Button>
</Form>
</Container>
</div>
)
}
componentDidMount (){
const {startCount} = this.props
this.setState({
count: startCount
})
this.doIntervalChange()
}
componentDidMount (){
this.myInterval = setInterval(() => {
this.setState(prevState => {
const newCount = prevState.count - 1;
if (newCount == 0) {
clearInterval(this.myInterval);
}
return { count: newCount };
});
}, 1000);
}
componentWillMount (){
clearInterval(this.myInterval)
}
}

Related

State won't update

I'm working on order system for my portfolio and I need your help.
for some reason one of the state values won't update while other does.
state = {
currOrder: {
createdAt: Date.now(),
totalPrice: 0,
lastUpdated: Date.now(),
notes: '',
products: [],
miniClient: {
_id: '',
fullName: ''
}
},
client: this.props.client
}
componentDidMount() {
if (this.props.currOrder) {
const currOrder = this.props.currOrder
this.setState({ currOrder })
} else {
this.setState({ currOrder: { ...this.state.currOrder, miniClient: { _id: this.state.client._id, fullName: this.state.client.fullName } } })
}
}
onHandleChange = (ev) => {
if (ev.target) {
const { target } = ev
const field = target.name
const value = target.type === 'number' ? +target.value : target.value
this.setState((prevState) => ({ currOrder: { ...prevState.currOrder, [field]: value } }))
}
}
getOrderLastUpdate = () => {
const updateDate = Date.now()
this.setState({ currOrder: { ...this.state.currOrder, lastUpdated: updateDate } }, () => { console.log(this.state.currOrder) })
}
onSubmitOrder = () => {
const { currOrder } = this.state
if (!currOrder._id) {
this.props.addOrder(currOrder)
this.props.isEditModalOpen()
} else {
this.getOrderLastUpdate()
this.props.updateOrder(currOrder)
this.props.isEditModalOpen()
}
}
render() {
const { notes, totalPrice, lastUpdated } = this.state.currOrder
const { client } = this.props
return (
<div className="order-edit">
<div>{client.fullName}</div>
<div>{utilService.formattedDates(lastUpdated)} : עודכן לאחרונה</div>
<div className="order-edit-info-holder">
<input type="number"
name="totalPrice"
value={totalPrice}
onChange={this.onHandleChange} />
<label htmlFor="totalPrice">מחיר</label>
</div>
<div className="order-edit-info-holder">
<input type="text"
name="notes"
value={notes}
onChange={this.onHandleChange} />
<label htmlFor="totalPrice">הערות</label>
</div>
<div className="order-edit-btns-container">
<button onClick={this.onSubmitOrder}>שמור</button>
<button onClick={this.props.isEditModalOpen}>בטל</button>
</div>
</div>
)
}
for some reason it refuses to update the lastUpdated value (as all other values are working fine :-()
Am I doing something wrong?
as for now the CB for getOrderLastUpdate function (console.log) won't even work.

How to reset interval and call api with interval in a function in react js

Hello I wanted to reset my set interval whenever my function is been called iam calling my interval in componentDidmount in react js and I want it to reset previous interval whenever that function is called iam also changing the value of api in that same function and now i want it to behave with the changes. The function is all three of the keyPressed Below is my code.
import React, { Component } from "react";
import { HotKeys } from "react-hotkeys";
import Axios from "axios";
class Test extends Component {
constructor(props) {
super(props);
this.state = {
seconds: 3,
color: null,
items: [],
currentItem: [],
index: 0
};
this.handleChange = this.handleChange.bind(this);
this.keyMap = {
DONT_APPLIES: ["a", "A"],
APPLIES: ["s", "S"],
STRONGLY_APPLIES: ["d", "D"]
};
this.handlers = {
DONT_APPLIES: e => {
this.keyPressed();
},
APPLIES: e => {
this.keyPressed1();
},
STRONGLY_APPLIES: e => {
this.keyPressed2();
}
};
}
keyPressed(e) {
const { index, items } = this.state;
const nextQuestion = index + 1;
this.setState({ currentItem: items[nextQuestion], index: nextQuestion });
console.log(this.state);
}
keyPressed1(e) {
const { index, items } = this.state;
const nextQuestion = index + 1;
this.setState({ currentItem: items[nextQuestion], index: nextQuestion });
console.log(this.state);
}
keyPressed2(e) {
const { index, items } = this.state;
const nextQuestion = index + 1;
this.setState({ currentItem: items[nextQuestion], index: nextQuestion });
console.log(this.state);
}
handleChangeColor = newColor => {
this.setState({
color: newColor
});
};
componentDidMount() {
this.myInterval = setInterval(() => {
const { seconds } = this.state;
if (seconds > 0) {
this.setState(({ seconds }) => ({
seconds: seconds - 1
}));
} else if (seconds == 0) {
return this.handleChangeColor("#840000");
}
}, 1000);
Axios.get("https://jsonplaceholder.typicode.com/users")
.then(response => {
console.log(response);
this.setState({
items: response.data.result.items,
currentItem: response.data.result.items[0],
index: 0
});
})
.catch(error => {
console.log(error);
});
}
componentWillUnmount() {
clearInterval(this.myInterval);
}
render() {
const { seconds } = this.state;
const timebox = {
width: "50px",
height: "20px"
};
const { currentItem } = this.state;
return (
<HotKeys keyMap={this.keyMap} handlers={this.handlers}>
<div id="wrapper" class="myleaty">
<div class="myleaty-holder">
<div class="container">
<div style={{ background: this.state.color }} class="myleaty-box">
<div style={timebox}>
<h2>{seconds}</h2>
</div>
<div class="logo">
<a href="#">
<img src="images/logo.png" alt="leaty" />
</a>
</div>
<p key={currentItem.id}>{currentItem.pqDetail}</p>
<div class="btn-row">
<button className="btn btn1">Does not Applies</button>
<button className="btn">Applies</button>
<button className="btn btn1">Strongly Applies</button>
</div>
</div>
</div>
</div>
</div>
</HotKeys>
);
}
}
export default Test;

ReactJS Stopwatch, how to handle localstorage data

i have component where i count time (Stopwatch). everything is working fine. Start, stop of the clock reset. I wanted to add functionality that when i stop clock (handleTimerStop) set current state to localstorage in case if i close browser and want to return and want to start where i left clock paused. So when i stop clock items are setup to localstorage but when i want to restart clock it doesn't take data from local storage but start from scratch. Could you please help? also it will be great if someone can optimsie my code becasue i feel it can be done better.
thanks
import React, { Component } from "react";
export default class Timer extends Component {
constructor(props) {
super(props);
this.state = {
timerStarted: false,
timerStopped: true,
hours: 0,
minutes: 0,
seconds: 0
};
}
componentDidMount() {
if (!localStorage.getItem("sec") === null) {
this.setState({
seconds: localStorage.getItem("sec")
});
}
if (!localStorage.getItem("min") === null) {
this.setState({
seconds: localStorage.getItem("min")
});
}
if (!localStorage.getItem("hour") === null) {
this.setState({
seconds: localStorage.getItem("hours")
});
}
}
handleTimerStart = e => {
e.preventDefault();
if (localStorage.getItem("sec") === null) {
this.setState({
seconds: 0
});
} else {
this.setState({
seconds: localStorage.getItem("sec")
});
}
if (localStorage.getItem("min") === null) {
this.setState({
minutes: 0
});
} else {
this.setState({
minutes: localStorage.getItem("min")
});
}
if (localStorage.getItem("hour") === null) {
this.setState({
hours: 0
});
} else {
this.setState({
hours: localStorage.getItem("hour")
});
}
if (this.state.timerStopped) {
this.timer = setInterval(() => {
this.setState({ timerStarted: true, timerStopped: false });
if (this.state.timerStarted) {
if (this.state.seconds >= 60) {
this.setState(prevState => ({
minutes: prevState.minutes + 1,
seconds: localStorage.getItem("sec")
}));
}
if (this.state.minutes >= 60) {
this.setState(prevState => ({
hours: prevState.hours + 1,
minutes: localStorage.getItem("min"),
seconds: localStorage.getItem("sec")
}));
}
this.setState(prevState => ({ seconds: prevState.seconds + 1 }));
}
}, 1000);
}
};
handleTimerStop = () => {
this.setState({ timerStarted: false, timerStopped: true });
clearInterval(this.timer);
localStorage.setItem("sec", this.state.seconds);
localStorage.setItem("min", this.state.minutes);
localStorage.setItem("hour", this.state.hours);
};
handelResetTimer = () => {
this.setState({
timerStarted: false,
timerStopped: true,
hours: 0,
minutes: 0,
seconds: 0
});
};
render() {
return (
<div className="container">
<h2 className="text-center"> React Based Timer </h2>
<div className="timer-container">
<div className="current-timer">
{this.state.hours +
":" +
this.state.minutes +
":" +
this.state.seconds}
</div>
<div className="timer-controls">
<button className="btn btn-success" onClick={this.handleTimerStart}>
Start Timer
</button>
<button className="btn btn-alert" onClick={this.handleTimerStop}>
Stop Timer
</button>
<button className="btn btn-info"> Capture Time </button>
<button className="btn btn-danger" onClick={this.handelResetTimer}>
{" "}
Reset!{" "}
</button>
</div>
</div>
</div>
);
}
}
These comparations are your problem.
!null === null or !'23' === null ... false always.
if (!localStorage.getItem("sec") === null) {
this.setState({
seconds: localStorage.getItem("sec")
});
}
if (!localStorage.getItem("min") === null) {
this.setState({
seconds: localStorage.getItem("min")
});
}
if (!localStorage.getItem("hour") === null) {
this.setState({
seconds: localStorage.getItem("hours")
});
}
This ain't an answer to your concrete question, but imo. a better approach at your code
This implementation is
independant of the render interval,
only writes to localStorage when you start/stop/reset it
and is not getting out of sync (even if it does not get rendered at all)
.
import React, { Component } from "react";
export default class Timer extends Component {
constructor(props) {
super(props);
try {
this.state = JSON.parse(localStorage.getItem(this.props.localStorage));
} catch (error) {}
if (!this.state) {
this.state = this.saveChanges({
running: false,
value: 0
});
}
}
componentWillMount() {
if (this.state.running) {
this.timer = setInterval(
() => this.forceUpdate(),
this.props.interval | 0
);
}
}
componentWillUnmount() {
if (this.state.running) {
clearInterval(this.timer);
}
}
saveChanges(state) {
console.log("saveChanges", this.props.localStorage, state);
if (this.props.localStorage) {
localStorage.setItem(this.props.localStorage, JSON.stringify(state));
}
return state;
}
start = () => {
const now = Date.now();
this.setState(({ running, value }) => {
if (running) return null;
this.timer = setInterval(
() => this.forceUpdate(),
this.props.interval | 0
);
return this.saveChanges({
running: true,
value: value - now
});
});
};
stop = () => {
const now = Date.now();
this.setState(({ running, value }) => {
if (!running) return null;
clearInterval(this.timer);
return this.saveChanges({
running: false,
value: value + now
});
});
};
reset = () => {
const now = Date.now();
this.setState(({ running, value }) => {
return this.saveChanges({
running: false,
value: 0
});
//just reset the timer to 0, don' stop it
//return this.saveChanges({
// running,
// value: running? -now: 0
//});
});
};
render() {
const {
start, stop, reset,
state: { running, value }
} = this;
const timestamp = running ? Date.now() + value : value;
const h = Math.floor(timestamp / 3600000);
const m = Math.floor(timestamp / 60000) % 60;
const s = Math.floor(timestamp / 1000) % 60;
const ms = timestamp % 1000;
const _ = (nr, length = 2, padding = 0) =>
String(nr).padStart(length, padding);
return (
<div className="container">
<h2 className="text-center"> React Based Timer </h2>
<div className="timer-container">
<div className="current-timer">
{_(h) + ":" + _(m) + ":" + _(s) + "." + _(ms, 3)}
</div>
<div className="timer-controls">
<button className="btn btn-success" onClick={start}>
Start Timer
</button>
<button className="btn btn-alert" onClick={stop}>
Stop Timer
</button>
<button className="btn btn-danger" onClick={reset}>
Reset!
</button>
</div>
</div>
</div>
);
}
}
check this Sandbox out

In React, how should I pass a starting elapsed time to a stopwatch component and start a running incrementer from that elapsed time?

I can get a static elapsed seconds to display based on the pulled start time but I can't get the elapsed seconds to then continue counting. I know I probably shouldn't be using the props to update a state in the child but even without that I couldn't get it to work and tried that as a workaround. Any help is appreciated.
Parent looks like this:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
elapsedSeconds: -1
};
this.changeElapsedSecondsParent = this.changeElapsedSecondsParent.bind(this);
}
changeElapsedSecondsParent(newElapsed) {
this.setState({
elapsedSeconds: newElapsed
});
}
render() {
const { elapsedSeconds } = this.state;
return (
<div>
<Stopwatch
elapsedSeconds={elapsedSeconds}
changeElapsed={this.changeElapsedSecondsParent}
/>
</div>
);
}
}
Child stopwatch looks like this:
const formattedSeconds = (sec) =>
~~(sec / 60) +
':' +
('0' + sec % 60).slice(-2)
export class Stopwatch extends React.Component {
constructor(props) {
super(props);
this.state = {
secondsElapsed: -1,
laps: [],
lastClearedIncrementer: null
};
this.incrementer = null;
this.handleStartClick = this.handleStartClick.bind(this);
this.handleStopClick = this.handleStopClick.bind(this);
this.handleResetClick = this.handleResetClick.bind(this);
this.handleLapClick = this.handleLapClick.bind(this);
}
componentDidMount() {
if(this.state.secondsElapsed < 0) {
const getElapsedTime = async () => {
try{
const response = await fetch(`api url`);
if(response.ok){
let jsonResponse = await response.json();
/* start getting seconds elapsed since start */
let currentServerTime = new Date(jsonResponse[0].currentTimeStamp).getTime() /1000;
let currentD = Math.floor(new Date().getTime()/1000);
let deltaDate = (currentServerTime-currentD);
let raceStartTime = new Date(jsonResponse[0].startTime).getTime()/1000 - deltaDate;
let secondsElapsedSinceStart = currentD - raceStartTime;
/* end getting seconds elapsed since start */
this.props.changeElapsed(secondsElapsedSinceStart);
}
}
catch(error){
console.log(error);
}
}
getElapsedTime();
let newElapsed = this.props.elapsedSeconds;
this.incrementer = setInterval( () =>
this.setState({
secondsElapsed: newElapsed + 1
})
, 1000);
} else {
this.incrementer = setInterval( () =>
this.setState({
secondsElapsed: this.state.secondsElapsed + 1
})
, 1000);
}
}
handleStartClick() {
/* start post request */
const pushTime = async () => {
try {
const response = await fetch('apiurl', {
method: 'POST',
body: JSON.stringify({"startTime": "'2018-08-26 16:57:09'"})
})
if(response.ok){
const jsonResponse = await response.json();
return jsonResponse;
}
throw new Error('Request failed!');
} catch(error) {
console.log(error);
}
}
pushTime();
}
handleStopClick() {
clearInterval(this.incrementer);
this.setState({
lastClearedIncrementer: this.incrementer
});
}
handleResetClick() {
clearInterval(this.incrementer);
this.setState({
secondsElapsed: 0,
laps: []
});
}
handleLapClick() {
this.setState({
laps: this.state.laps.concat([this.props.elapsedSeconds])
})
}
render() {
return (
<div className="stopwatch">
<h1 className="stopwatch-timer">{formattedSeconds(this.state.secondsElapsed)}</h1>
{(this.props.elapsedSeconds === 0 ||
this.incrementer === this.state.lastClearedIncrementer
? <Button className="start-btn" onClick={this.handleStartClick.bind(this)}>start</Button>
: <Button className="stop-btn" onClick={this.handleStopClick.bind(this)}>stop</Button>
)}
{(this.props.elapsedSeconds !== 0 &&
this.incrementer !== this.state.lastClearedIncrementer
? <Button onClick={this.handleLapClick.bind(this)}>lap</Button>
: null
)}
{(this.props.elapsedSeconds !== 0 &&
this.incrementer === this.state.lastClearedIncrementer
? <Button onClick={this.handleResetClick.bind(this)}>reset</Button>
: null
)}
<ul className="stopwatch-laps">
{ this.state.laps.map((lap, i) =>
<li className="stopwatch-lap"><strong>{i + 1}</strong>/ {formattedSeconds(lap)}</li>)
}
</ul>
</div>
);
}
}
const Button = (props) =>
<button type="button" {...props} className={"btn " + props.className } />;
I found it easier to define a constant in the constructor like:
this.deltaTime = null;
Then I created a changeDeltaTime function:
changeDeltaTime(newTime) {
this.deltaTime = newTime
}
lastly, I updated that deltaTime inside the promiseand after the response within the componentDidUpdate() lifecycle method.
await this.changeDeltaTime(deltaDate);
In render, I waited the promise to be resolved through a prop passed by parent
return !this.props.finishedGet ? <span>Waiting on fetch...</span> : (this.renderStopwatch(this.state.time))
This also involves the renderStopwatch function to be created but it basically just houses what should be created once the promise resolves.

Start the timer when button is clicked in React.Js

How do you make it so that whenever you click the start button, only then will the timer starts. Because right now, it starts at will.
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = { seconds: 0 };
}
tick() {
this.setState(prevState => ({
seconds: prevState.seconds + 1
}));
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div>
Seconds: {this.state.seconds}
<br />
<button onClick={this.tick}> Start </button>
</div>
);
}
}
ReactDOM.render(<Timer />, mountNode);
What should I put in the onClick attribute?
You will need to bind 'tick' to the component in the constructor and move the code for starting the timer from 'componentDidMount' to 'tick' like so:
class Timer extends React.Component {
constructor(props) {
super(props);
this.state = { seconds: 0 };
this.tick = this.tick.bind(this); // bind to the component
}
tick() {
// start timer after button is clicked
this.interval = setInterval(() => {
this.setState(prevState => ({
seconds: prevState.seconds + 1
}));
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div>
Seconds: {this.state.seconds}
<br />
<button onClick={this.tick}> Start </button>
</div>
);
}
}
ReactDOM.render(<Timer />, mountNode);
Hope that helps.
This is how we can achieve the same using React Hooks.
const Timer = () => {
const [isActive, setIsActive] = useState(false);
const [seconds, setSeconds] = useState(0);
useEffect(() => {
let timer = null;
if(isActive){
timer = setInterval(() => {
setSeconds((seconds) => seconds + 1);
}, 1000);
}
return () => {
clearInterval(timer);
};
});
return (
<div>
Seconds: {seconds}
<br />
<button onClick={()=>{
setIsActive(true);
}}> Start </button>
</div>
);
};

Categories

Resources