logo

react-hot-toastのtoast.custom()を共通利用する

2024-01-06
11 months ago

開発環境

  • next 14.0.4
  • react-hot-toast 2.4.1
  • tailwindcss 3

前提

react-hot-toastはの基本的な使い方の説明は省きます。

また、プロジェクトにreact-hot-toastはインストール済みで、各コンポーネントからtoastAPIが利用できる状態を想定しています。

本題

react-hot-toastは簡単にトーストを導入できるライブラリです。

デフォルトでsuccess, errorをサポートしており、以下のように呼び出すことで簡単にトーストを利用できます。

toast.success('ログインしました')
toast.error('ログインに失敗しました');

また、それぞれのスタイルをカスタマイズする際は以下のようにToasterコンポーネントのtoastOptionsで定義できます。

<Toaster
  toastOptions={{
    style: {
      minWidth: 360,
      height: 40,
      padding: 8,
      borderRadius: 8,
    },
    success: {
      style: {
        border: '1px solid #...',
        background: '#...',
        color: '#...',
      },
    },
    error: {
      style: {
        border: '1px solid #...',
        background: '#...',
        color: '#...',
      },
      icon: <CustomIcon />,
    },
  }}
  position="top-center"
/>

customはいつ使う?

何かデータを操作したときのフィードバックとしてsuccess, errorで事足りることがほとんどだと思いますが、それら以外の通知(例、警告や補足など)を実装したいときにcustomを利用すると便利です。

ただ、toast.custom()はデフォルトのスタイルが当たっていません。

その分カスタマイズ性は高く用途によってはとても便利です。

customの困りどころ

前述したように、デフォルトのスタイルが当たっていない為、デフォルトのsuccess, errorと同じように利用する(例、色違いなど)となるとアニメーション含めスタイルを当てていくことになります。

また、JSXを渡す形になるので無駄なコードが増える可能性もあり、少し共通利用しにくいです。


そこで、カスタム用の関数を作成してみました。

alert以外も任意のものを追加できる形にしています。

export const customToast = {
  alert: (message: string): ReactNode =>
    toast.custom(({ visible }) => (
      <div
        className={`
          flex h-10 min-w-[360px] items-center gap-2 rounded-lg
          border border-yellow-400 bg-yellow-50 p-2
          text-sm leading-5 text-yellow-400 shadow
          ${visible ? 'animate-scale-in-top' : 'animate-scale-out-top'}
        `}
      >
        <CustomIcon />
        <span>{message}</span>
      </div>
    )),
};
toaster.tsx

呼び出しはこんな感じです。

<button onClick={() => customToast.alert('こんにちは')}>
  こんにちはボタン
</button>

おまけ

アニメーションの部分をTailwindで再現するためにanimate-scale-in-topanimate-scale-out-topの2つのクラスを追加しています。

import type { Config } from 'tailwindcss';

const config: Config = {
	...(省略)
  theme: {
    extend: {
      animation: {
        'scale-in-top':
          'scale-in-top 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940)   both',
        'scale-out-top':
          'scale-out-top 0.1s cubic-bezier(0.550, 0.085, 0.680, 0.530)   both',
      },
      keyframes: {
        'scale-in-top': {
          '0%': {
            transform: 'scale(0)',
            'transform-origin': '50% 0%',
            opacity: '1',
          },
          to: {
            transform: 'scale(1)',
            'transform-origin': '50% 0%',
            opacity: '1',
          },
        },
        'scale-out-top': {
          '0%': {
            transform: 'scale(1)',
            'transform-origin': '50% 0%',
            opacity: '1',
          },
          to: {
            transform: 'scale(0)',
            'transform-origin': '50% 0%',
            opacity: '1',
          },
        },
      },
    },
  },
};
export default config;
tailwind.config.ts

下のサイトで簡単にアニメーションクラスを拡張できるのでぜひ活用してみてください。

参照