Version 0 : this works....
const getCurrentDate = () => new Date();
[datetime, setDatetime] = useState(new Date())
tick(setDateTime(getCurrentDate()))
setInterval(tick,1000)
return {(
<div>{datetime}</div>
)
}
Version 1:
issue: why setInterval?
import React, { useReducer, useEffect, useCallback } from 'react';
import './Clock.scss';
const getCurrentDate = () => new Date();
const getMonthStr = (month) => {
const monthNames = [
'JAN',
'MAR',
'APR',
'MAY',
'JUN',
'JUL',
'AUG',
'SEP',
'OCT',
'NOV',
'DEC',
];
return monthNames[month];
};
const getWeekStr = (week) => {
const weekNames = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
return weekNames[week];
};
const getDateString = (dateObj) =>
`${dateObj.getDate()} ${getMonthStr(dateObj.getMonth())} ${getWeekStr(
dateObj.getDay()
)}`;
const pad = (number) => (+number < 10 ? `0${number}` : number);
const getTimeString = (dateObj) =>
`${pad(dateObj.getHours())}:${pad(dateObj.getMinutes())}:${pad(
dateObj.getSeconds()
)}`;
const dateTimeReducer = (currState, action) => {
clearInterval(currState.intervalId);
return {
date: getDateString(action.dateObj),
time: getTimeString(action.dateObj),
};
};
const Clock = (props) => {
// cache tick function
const tick = useCallback(() => {
dispatch({ dateObj: getCurrentDate() });
}, []);
const [dateTimeState, dispatch] = useReducer(dateTimeReducer, {
date: getDateString(getCurrentDate()),
time: getTimeString(getCurrentDate()),
});
useEffect(() => {
const id = setInterval(tick, 1000);
return () => {
//clean up
clearInterval(id);
};
});
return (
<React.Fragment>
{dateTimeState.date} {dateTimeState.time}
</React.Fragment>
);
};
export default Clock;
Version 2:
issue: what's better then settimeout?
useEffect(() => {
const id = setTimeout(tick, 1000);
return () => {
//clean up
clearTimeout(id);
};
});
Version 3:
issue: how can i call requestAnimationFrame once only ? why do have have to keep creating the animation and cancel at every rerender.
import React, { useReducer, useEffect, useCallback } from 'react';
import './Clock.scss';
const getCurrentDate = () => new Date();
const getMonthStr = (month) => {
const monthNames = [
'JAN',
'MAR',
'APR',
'MAY',
'JUN',
'JUL',
'AUG',
'SEP',
'OCT',
'NOV',
'DEC',
];
return monthNames[month];
};
const getWeekStr = (week) => {
const weekNames = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
return weekNames[week];
};
const getDateString = (dateObj) =>
`${dateObj.getDate()} ${getMonthStr(dateObj.getMonth())} ${getWeekStr(
dateObj.getDay()
)}`;
const pad = (number) => (+number < 10 ? `0${number}` : number);
const getTimeString = (dateObj) =>
`${pad(dateObj.getHours())}:${pad(dateObj.getMinutes())}:${pad(
dateObj.getSeconds()
)}`;
const dateTimeReducer = (currState, action) => {
clearInterval(currState.intervalId);
return {
date: getDateString(action.dateObj),
time: getTimeString(action.dateObj),
};
};
const Clock = (props) => {
// cache tick function
const tick = useCallback(() => {
dispatch({ dateObj: getCurrentDate() });
}, []);
const [dateTimeState, dispatch] = useReducer(dateTimeReducer, {
date: getDateString(getCurrentDate()),
time: getTimeString(getCurrentDate()),
});
useEffect(() => {
const animation = window.requestAnimationFrame(tick, 1000);
return () => cancelAnimationFrame(animation);
});
return (
<React.Fragment>
{dateTimeState.date} {dateTimeState.time}
</React.Fragment>
);
};
export default Clock;
v4
Issue: can you spot the bug?
import React, { useReducer, useEffect, useCallback } from 'react';
import './Clock.scss';
const getCurrentDate = () => new Date();
const getMonthStr = (month) => {
const monthNames = [
'JAN',
'MAR',
'APR',
'MAY',
'JUN',
'JUL',
'AUG',
'SEP',
'OCT',
'NOV',
'DEC',
];
return monthNames[month];
};
const getWeekStr = (week) => {
const weekNames = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
return weekNames[week];
};
const getDateString = (dateObj) =>
`${dateObj.getDate()} ${getMonthStr(dateObj.getMonth())} ${getWeekStr(
dateObj.getDay()
)}`;
const pad = (number) => (+number < 10 ? `0${number}` : number);
const getTimeString = (dateObj) =>
`${pad(dateObj.getHours())}:${pad(dateObj.getMinutes())}:${pad(
dateObj.getSeconds()
)}`;
const dateTimeReducer = (currState, action) => {
clearInterval(currState.intervalId);
return {
date: getDateString(action.dateObj),
time: getTimeString(action.dateObj),
};
};
const Clock = (props) => {
// cache tick function
const tick = useCallback(() => {
dispatch({ dateObj: getCurrentDate() });
}, []);
const requestAnimation = useCallback((fn) => {
const reqRef = requestAnimationFrame(fn);
return reqRef;
}, []);
const [dateTimeState, dispatch] = useReducer(dateTimeReducer, {
date: getDateString(getCurrentDate()),
time: getTimeString(getCurrentDate()),
});
useEffect(() => {
const requestRef = requestAnimation(tick);
return () => cancelAnimationFrame(requestRef);
});
return (
<React.Fragment>
{dateTimeState.date} {dateTimeState.time}
</React.Fragment>
);
};
export default Clock;
v5
issue: the delay makes the second tick a few seconds slower then actual, so v6 will be v4, updates about 60 times per second
import React, { useReducer, useEffect, useCallback } from 'react';
import './Clock.scss';
const getCurrentDate = () => new Date();
const getMonthStr = (month) => {
const monthNames = [
'JAN',
'MAR',
'APR',
'MAY',
'JUN',
'JUL',
'AUG',
'SEP',
'OCT',
'NOV',
'DEC',
];
return monthNames[month];
};
const getWeekStr = (week) => {
const weekNames = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
return weekNames[week];
};
const getDateString = (dateObj) =>
`${dateObj.getDate()} ${getMonthStr(dateObj.getMonth())} ${getWeekStr(
dateObj.getDay()
)}`;
const pad = (number) => (+number < 10 ? `0${number}` : number);
const getTimeString = (dateObj) =>
`${pad(dateObj.getHours())}:${pad(dateObj.getMinutes())}:${pad(
dateObj.getSeconds()
)}`;
const dateTimeReducer = (currState, action) => {
clearInterval(currState.intervalId);
return {
date: getDateString(action.dateObj),
time: getTimeString(action.dateObj),
};
};
const Clock = (props) => {
// cache tick function
const tick = useCallback(() => {
console.log('triggered');
dispatch({ dateObj: getCurrentDate() });
}, []);
// credit Joelambert https://gist.github.com/joelambert/1002116#gistcomment-1953925
const requestAnimation = useCallback((fn, delay) => {
const start = new Date().getTime();
let handle;
const loop = () => {
const current = new Date().getTime();
const delta = current - start;
delta >= delay ? fn() : (handle = requestAnimationFrame(loop));
};
handle = requestAnimationFrame(loop);
return handle;
}, []);
// const requestAnimation = useCallback((fn) => {
// const reqRef = requestAnimationFrame(fn);
// return reqRef;
// }, []);
const [dateTimeState, dispatch] = useReducer(dateTimeReducer, {
date: getDateString(getCurrentDate()),
time: getTimeString(getCurrentDate()),
});
useEffect(() => {
const requestRef = requestAnimation(tick, 1000);
return () => cancelAnimationFrame(requestRef);
});
return (
<React.Fragment>
{dateTimeState.date} {dateTimeState.time}
</React.Fragment>
);
};
export default Clock;
import React, {useCallback, useEffect, useReducer} from 'react';
import './Clock.scss';
import {getCurrentDate, getDateString, getTimeString} from "../../Utils/DateTimeUtils";
const dateTimeReducer = (currState, action) => {
return {
date: getDateString(action.dateObj),
time: getTimeString(action.dateObj),
};
};
const Clock = (props) => {
const [dateTimeState, dispatch] = useReducer(dateTimeReducer, {
date: getDateString(getCurrentDate()),
time: getTimeString(getCurrentDate()),
});
// cache tick function
const tick = useCallback(() => {
setTimeout(() => {
dispatch({dateObj: getCurrentDate()});
return requestAnimationFrame(tick)
},500)
}, []);
useEffect(() => {
console.log('this is run')
const requestRef = requestAnimationFrame(tick)
return () => cancelAnimationFrame(requestRef);
},[]);
return (
<div className={`clock ${props.clockClassNames&&props.clockClassNames}`}>
{console.log('i am re-rendered')}
<div className={`clock-time ${props.timeClassNames && props.timeClassNames}`}>
{dateTimeState.time}
</div>
<div className={`clock-date ${props.dateClassNames && props.dateClassNames}`}>
{dateTimeState.date}
</div>
</div>
);
};
export default Clock;
- datetimeutil.js
const pad = (number) => (+number < 10 ? `0${number}` : number);
export const getCurrentDate = () => new Date();
const getWeekStr = (week) => {
const weekNames = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
];
return weekNames[week];
};
const getMonthStr = (month) => {
const monthNames = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'DEC',
];
return monthNames[month];
};
export const getDateString = (dateObj) =>
`${dateObj.getDate()} ${getMonthStr(dateObj.getMonth())} ${getWeekStr(
dateObj.getDay()
)}`;
export const getTimeString = (dateObj) =>
`${pad(dateObj.getHours())}:${pad(dateObj.getMinutes())}`;