🕓

パフォーマンスを意識してReactで現在時刻を毎秒更新し続ける

2024/06/08に公開

はじめに

株式会社メンヘラテクノロジーでエンジニアをしているandmohikoです。

メンヘラテクノロジーではDIALS2という通話アプリを開発しています。アプリ内では通話の残り時間や支払い期限など、現在時刻を参照する場面がいくつかあります。今回はパフォーマンスについても意識しながらアプリケーション内で現在時刻を毎秒更新し続ける方法について書きました。

問題意識

「現在時刻を取得し続ける」するというシンプルな要件を満たすために、まずはnew Date()を使用して現在時刻を取得する方法が思い浮かびます。
しかし、new Date()は呼ばれた時点での時刻を返すだけで、その後も更新され続けるわけではありません。

カスタムフックの実装

そこで、毎秒更新するためにuseStateuseEffectを素直に組み合わせた実装が思い浮かびます。useEffectsetIntervalを使用して毎秒処理を走らせ、現在時刻をコンポーネントの状態として設定することによって行われます。これにより、Reactは状態の変更を検知し、関連するコンポーネントを再レンダリングします。

useCurrentTime.tsx
// 現在時刻を管理するカスタムフック
function useCurrentTime() {
  const [currentTime, setCurrentTime] = useState(new Date());

  useEffect(() => {
    const intervalId = setInterval(() => {
      setCurrentTime(new Date());
    }, 1000);
    return () => clearInterval(intervalId);
  }, []);

  return currentTime;
}

こちらのカスタムフックを通話画面のコンポーネントで使用すれば通話の残り時間が毎秒更新されます。
挙動上は問題ないように思えますが、実際にはこの処理が毎秒行われるため、不必要に多くの再レンダリングが発生し、複雑な画面ではパフォーマンスに影響を与える可能性があります。
特に、通話画面ではWebRTCの接続なども行っているため、通話画面全体が毎秒再レンダリングされてしまい、通話機能のパフォーマンスに影響を与えるのは避けたいです。

コンポーネントの実装

そこで、現在時刻を表示するだけのコンポーネントを用意し、再レンダリングの範囲を狭めます。

CurrentTimeDisplay.tsx
// 現在時刻を表示するコンポーネント
const CurrentTimeDisplay() => {
  const currentTime = useCurrentTime();
  return <div>現在時刻: {currentTime.toLocaleTimeString()}</div>;
}

おわりに

今回のカスタムフックを用いたカウントダウンタイマーの実装により、Reactアプリケーション内での時間管理がより簡単かつ効率的になりました。カスタムフックの設計は、コードの再利用性を高め、他のプロジェクトやコンポーネントでも容易に適用できるため、開発のスピードと品質を向上させる助けとなります。

この記事を通じて、カスタムフックの理解とその実践的な活用を皆様のプロジェクトに役立ててください。

Discussion