📌

時間差でdispatchを行うカスタムフックを作る

2021/08/22に公開

はじめに

画面上に通知を出した際、一定時間後に自動で削除したかったのでカスタムフックを作りました。

やりたいこと

  • 画面上に通知を表示する
  • 通知を表示後、一定時間経過後にdispatchを行う。それにより通知を削除する。

実装

カスタムフック

useDispatchTimer.ts
import { ActionCreatorWithPayload } from '@reduxjs/toolkit';
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';

type ReduxActionCreator<T> = ActionCreatorWithPayload<T, string>;
type Payload<T> = T[];

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useDispatchTimer = <T>(actionCreator: ReduxActionCreator<T>, payload: Payload<T>, time?: number) => {
    const dispatch = useDispatch();
    // redux-thunkで1つのactionを複数回発行する場面が存在したため、配列にまとめてPromise.allで実行
    const dispatchers = () => payload.map((item) => dispatch(actionCreator(item)));

    useEffect(() => {
        const timer = setTimeout(() => {
            void Promise.all(dispatchers());
        }, time || 5000);

        return () => {
            clearTimeout(timer);
        };
    });
};

使用時

ListPageNoticeSelector.ts
export const ListPageNoticeSelector = () => {
    const notice = useSelector((store: RootState) => store.hoge.listPageNotice);
    useDispatchTimer(hogeAction.setNotice, [{ text: '', type: 'listPage' }]);

    return <>{notice && <SystemMsg text={notice} />}</>;
};
  • 初回レンダリング時にuseDispatchTimerが走るが、useSelectorのメモ化によりレンダリングには影響なし
  • store.hoge.listPageNoticeが変化して再レンダリングされると、再度useDispatchTimerが走る
  • 一定時間後に通知が削除される

Discussion