📘

シングルトンパターンを利用してトーストの複数表示を行う

2022/04/27に公開

はじめに

トーストを複数表示するためにシングルトンパターンを利用したので、備忘録としてまとめます。

Vue-Toastificationを使用してトーストを表示する

弊社ではトーストの表示にVue-Toastificationというライブラリを使用しています。

Vue-Toastificationとは

トーストを簡単に実装できるライブラリです。
vueと名前についていますが、Reactでも使用できるようです。
https://vue-toastification.maronato.dev/

特徴

  • TypeScriptをサポートしている
  • トーストの表示や動作を簡単にカスタマイズできる
  • 表示の残時間をいい感じに表示、ホバー時には一時停止できる

実装例(シングルトンパターン利用しない)

タイトルやテキストを渡して、動的に変化するようにしたかったので、下記のように実装してみました。

export const toast = (props: {
  title: string
  text: string
}) => {
  const pluginOptions = {
    maxToasts: 10,
  }
  const toast = createToastInterface(pluginOptions)

  const content = {
    component: SToaster, // カスタマイズしたコンポーネントをセットする
    props: {
      title: props.title,
      text: props.text,
    },
  }
  toast(content, {
    type: TYPE.SUCCESS,
  })
}

ところが、createToastInterfaceが実行されるたびにインスタンスを生成してしまうため、新たに作成したトーストが元のトーストに被って表示されてしまいます。
インスタンスが複数作成される場合
そこで、シングルトンパターンを用いた実装を行うことにしました。

シングルトンパターンとは

  • デザインパターンのひとつ
  • クラスのインスタンスが1つしか生成されないことを保証する

https://qiita.com/shoheiyokoyama/items/c16fd547a77773c0ccc1

シングルトンパターンを用いる簡単な実装例

まずはシングルトンパターンを利用する簡単な例をご紹介します。

class MySingleton {
    private static instance: MySingleton
    // ポイント1: コンストラクタをprivateにする
    private constructor (){}

    // ポイント2: インスタンスを取得するためのstaticメソッドを作成する
    static getInstance() {
        if (MySingleton.instance) {
            return MySingleton.instance
        }
        MySingleton.instance = new MySingleton()
        return MySingleton.instance
    }
}

const instance1 = MySingleton.getInstance()
const instance2 = MySingleton.getInstance()

console.log(instance1 === instance2)  // True

実装のポイント💡

シングルトンパターン実装のポイントは2点です!

  1. コンストラクタをprivateにする
    クラス外でインスタンスの生成が行えないように、コンストラクタをprivateに設定します。

    private constructor (){}
    
  2. インスタンスを取得するためのstaticメソッドを作成する
    インスタンスの有無を確認し、インスタンスが存在しない場合のみ、インスタンスの生成を行います。

    static getInstance() {
        if (MySingleton.instance) {
            return MySingleton.instance
        }
        MySingleton.instance = new MySingleton()
        return MySingleton.instance
    }
    

シングルトンパターンを用いたVue-Toastificationの実装

クラス外からインスタンスを取得するためのstaticメソッドを直接使用しない点が異なりますが、上記の実装例とポイントは同じです。

vueToastification.ts
class Toastification {
  private static toastInterface: Toastification
  toast

  // ポイント1: コンストラクタをprivateにする
  private constructor() {
    const pluginOptions = {
      maxToasts: 10,
    }
    this.toast = createToastInterface(pluginOptions)
  }

  // ポイント2: インスタンスを取得するためのstaticメソッドを作成する
  private static getInterface() {
    if (Toastification.toastInterface) return this.toastInterface
    Toastification.toastInterface = new Toastification()
    return Toastification.toastInterface
  }

  static toast = (props: {title: string, text: string}) => {
    const toastInterface = Toastification.getInterface()
    const content = {
      component: SToaster,  // カスタマイズしたコンポーネントをセットする
      props: {
        title: props.title,
        text: props.text,
      },
    }
    toastInterface.toast(content, {
      type: TYPE.SUCCESS,
      closeButton: 'button',
    })
  }
}
export { toast }
index.vue
<script>
import { defineComponent } from '@vue/composition-api'
import { toast } from '~/vueToastification'

export default defineComponent({
  setup() {
    const onClick = () => {
      // toastを呼び出すことで、トーストが表示される
      toast({
        title: '成功',
        text: 'いい調子ですね',
      })
    }
    return { onClick }
  },
})
</script>

シングルトンパターンを使用してcreateToastInterfaceを一度だけ呼び出すようにしたことで、トーストが複数表示されるようになりました。
シングルトンパターンを使用した場合

おわりに

最後に宣伝ですが、sweeepではエンジニアを募集しています。ご興味のある方は下記リンクよりご応募お待ちしております!

https://corp.sweeep.ai/recruit

GitHubで編集を提案

Discussion