Reputation: 95
I am trying to build a timer component using the react-countdown-now package: https://www.npmjs.com/package/react-countdown-now#key.
I was having trouble to reset the timer so that it moves on to the next time on the schedule.
I have been trying to use key property in props it pass it in an array of times to wait till (it was in the documentation). In reality I would get these values of a schedule from a server side method.
Currently I have
Component:
<Countdown
date={Date.now() + 5000}
key = {timeDelays}
intervalDelay={0}
precision={3}
renderer={timerRenderer}
/>
Supporting functions and Values:
//These time values are most probably going to be in JSON format,
//and probably will contain EPOCH times for scheduled events
const timeDelays = [2000,4000,3000,15789,2345794];
// Random component
const Completionist = () => <span>You are good to go!</span>;
// Renderer callback with condition
const timerRenderer = ({ hours, minutes, seconds, completed }) => {
// if (completed) {
// Render a completed state
// return <Completionist />;
// } else {
// // Render a countdown
return <span>{hours}:{minutes}:{seconds}</span>;
//}
};
I want it to start with a countdown from the list and then when completed move onto the next schedule value from the list.
Upvotes: 2
Views: 5561
Reputation: 2703
This is a total change from the former answer, which used a class-based component.
First, we'll need to import React and React hooks to our component file.
import React, { useState } from 'react';
Next, we'll declare a React function component and use React hooks to maintain state.
function MyCountdownTimer({ times }) {
// a hook for the current time index
const [currentTimeIndex, setCurrentTimeIndex] = useState(0);
// a hook for the current time
const [currentTime, setCurrentTime] = useState(null);
// return a render
return (
<Countdown
date={currentTime}
key={currentTimeIndex}
onComplete={() => {
// dont's move to next time if just done with last time
if(times.length - 1 <= times.indexOf(currentTime)) return;
// move to next time index
setCurrentTimeIndex(currentTimeIndex + 1);
// reset current time
setCurrentTime(new Date(times[currentTimeIndex + 1]));
}}
renderer={({ hours, minutes, seconds, completed }) => {
// render completed
if (completed) return <span>You are good to go!</span>;
// render current countdown time
return <span>{hours}:{minutes}:{seconds}</span>;
}}
/>
);
}
An implementation of this would look something like so.
let times = [...] // an array of times
<MyCountdownTimer times={times} />
React hooks are still a bit new so for a better understanding on React Hooks you can follow this link https://reactjs.org/docs/hooks-intro.html.
NOTE
You need a way to tell what time you're currently on so within your component you'll have two things. The list of times(times
) as an array this should be passed as a prop as suggested in the code above, the index of the current time(currentTimeIndex
) as an integer and the current time(currentTime
) as a Date object.
You'll need to listen for when the timer hits zero using the onComplete
property to define a callback method, we do not update the component's state when the Countdown timer has been completed.
A key property on the Countdown component, this is meant to change for each time you want to reset the countdown timer and since we're incrementing the index to go to the next time we'll simply use the index of the current time.
I reduced the code of your renderer so you can render what you need to within the same function, except if you will be adding a lot more code in there than that.
This is using a function component with hooks to maintain state.
The date according to the documentation can be a date object.
Upvotes: 4
Reputation: 343
Just you need to change the value of key attribute key={new values or updated value}
so automatically re set the timer.
key This is one of React's internal component props and is used to identify the component. However, we can leverage this behaviour and use it to, for example, restart the countdown by passing in a new string or number.https://www.npmjs.com/package/react-countdown
Upvotes: 2
Reputation: 95
I guess my translated component would look like this
const WebPage = (props) => {
const timerState = {
times:[Date.now()+5000,Date.now()+12000,Date.now()+17000,Date.now()+22000],
currentTimeIndex: 0,
currentTime: Date.now(),
} ;
const timerRenderer = ({ hours, minutes, seconds, completed }) => {
if (completed) return <span> No more Scheduled time</span>;
return <span>{hours}:{minutes}:{seconds}</span>;
};
const completeTime = () => {
if (timerState.times.length - 1 <= times.indexOf(timerState.currentTime)) return;
// move to next time
timerState.currentTimeIndex++;
timerState.currentTime = new Date(timerState.times[timerState.currentTimeIndex+1])
};
return (
<Countdown
date={timerState.currentTime}
key = {timerState.currentTimeIndex}
onComplete={completeTime}
intervalDelay={0}
precision={3}
renderer={timerRenderer}
/>
)
}
It's not exactly working as it by default goes to "No more Scheduled time", and if I get rid of the if(completed) it just stays at 0:0:0.
Upvotes: 1