💬

【dayjs】React×TypeScriptでボタンを押してからの経過時間を表示

2023/05/29に公開

カウントダウンとか時計のアプリはあるけれど、
経過時間を表示するコードはあまりなかったので
今回はdayjsを使ったコードを投稿。

まだコードレビューしてもらっていないので、誤りがあれば修正しますm(__)m

dayjsをインストール

まずはインストールのコマンド入力。

$ npm install dayjs --save

ボタンを押したら時刻をuseStateに格納(更新)

時間を格納するuseStateと、ボタンを押されたら動く関数を用意して
関数でstateを更新するように実装。
ついでに表示用のJSXも書いておく。

import dayjs from 'dayjs';
import React, { useState } from 'react';

export const Test = () => {
  // ボタンを押した時刻のstateを用意
  const [timestamp, setTimestamp] = useState('');

  const increment = () => {
    // 現在時刻を取得してstateを更新
    const time = dayjs().format('YYYY-MM-DDTHH:mm:ss');
    setTimestamp(time);
  };
  
  return (
    <div>
     <p>前回ボタンを押した時間:{timestamp}</p>
      <p>経過時間:</p>
      <button type="submit" onClick={increment}>
        Button
      </button>
    </div>
  );
};

dayjsで経過時間を計算

経過時刻は現在の時刻からタイムスタンプの時刻を引くと計算できます。


export const Test = () => {
  const [timestamp, setTimestamp] = useState('');
  
  
  // ここに追記
  const [elapsedTime, setElapsedTime] = useState('');
  
   // 何回もレンダリングしてしまうのでUseEffectを使用
   useEffect(() => {
    const now = dayjs().format('YYYY-MM-DDTHH:mm:ss');
    const diffHour = dayjs(now).diff(dayjs(timestamp), 'hour');
    const diffMin = dayjs(now).diff(dayjs(timestamp), 'minute');
    const diffSec = dayjs(now).diff(dayjs(timestamp), 'second');
    setElapsedTime(`${diffHour}時間${diffMin % 60}${diffSec % 60}`);
  // timestampのstateが更新されるたびにレンダリング
  }, [timestamp])
  

  const increment = () => {
    const now = dayjs().format('YYYY-MM-DDTHH:mm:ss');
    setTimestamp(now);
  };
  ――――――――――――――――――――――――――――――――――
  // JSXにも追記
  <p>前回ボタンを押した時間:{timestamp}</p>
      <p>経過時間:{elapsedTime}</p>
  

これでボタンをおしてみると・・・
経過時間:0時間0分0秒になってしまう!

ボタンを押したらタイムスタンプを押して、
なおかつ今の時間との差を計算して表示なので
経過時間はいつだって0なのさ。

要するにボタンを押してから、経過時間を表示し続けることになる。

経過時間を表示し続ける。

表示し続けるということは、ボタンを押してから1秒単位でカウントアップしていく必要がある。
setIntervalとclearInterval使ってuseEffectの中身を修正。

先ほどのuseEffectの中を修正

  
  useEffect(() => {
    const interval = setInterval(() => {
      const now = dayjs().format('YYYY-MM-DDTHH:mm:ss');
      const diffHour = dayjs(now).diff(dayjs(timestamp), 'hour');
      const diffMin = dayjs(now).diff(dayjs(timestamp), 'minute');
      const diffSec = dayjs(now).diff(dayjs(timestamp), 'second');
      setElapsedTime(`${diffHour}時間${diffMin % 60}${diffSec % 60}`);
    }, 1000);
    return () => {
      clearInterval(interval);
    };
  }, [timestamp]);
  

これで動くようになりました!

初期表示が「経過時間:NaN時間NaN分NaN秒」になってしまう

初期表示時はタイムスタンプのstateが空の状態なので、当然NaNになります。
なので、ifを使って以下を追記。

  
  useEffect(() => {
   //空じゃなければ実行してねのif文
    if (timestamp !== '') {
      const interval = setInterval(() => {
	// 現在の時刻を取得
        const now = dayjs().format('YYYY-MM-DDTHH:mm:ss');
	//時、分、秒ごとに引いた時間を計算
        const diffHour = dayjs(now).diff(dayjs(timestamp), 'hour');
        const diffMin = dayjs(now).diff(dayjs(timestamp), 'minute');
        const diffSec = dayjs(now).diff(dayjs(timestamp), 'second');
	//stateに格納。60分、60秒を超えないように%60にする
        setElapsedTime(`${diffHour}時間${diffMin % 60}${diffSec % 60}`);
      }, 1000);
      return () => {
        clearInterval(interval);
      };
    }
  }, [timestamp]);
  

これで無事動きました!!

Discussion