Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails以外の開発一般

Better Stimulusガイド 06: コントローラ間通信にコールバックを使う(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

🔗 コントローラ間通信にコールバックを使う(翻訳)

  • 単一のStimulusJSコンポーネントで複数のロジックを管理したい場合
  • 機能を実行するために他のコントローラの値が必要な場合
  • あらゆるケースに対応するためにイベントをたくさん作りたくない場合

話を簡単にするために、以下の例ではカスタムイベントのコンストラクタが不要なjQueryを使っていますが、素のJavaScriptも使えます。

Bad

// first_controller.js
export default class extends Controller {
  setName(value) {
    this.name = value
    $(document).trigger('first_controller.nameChanged', this.name)
  }
}
// second_controller.js
export default class extends Controller {
  connect() {
    // このコントローラでは、UIを何らかのレンダリングするためのnameが必要
    $(document).on('first_controller.nameChanged', function(event, name) {
      // このnameで何らかの処理を行うコードをここに書く
      this.name = name
    }.bind(this))
  }
}

Good

// first_controller.js
export default class extends Controller {
  connect() {
    $(document).on('first_controller.state', function(event, callback) {
        callback(this)
      }.bind(this)
    )
  }

  setName(value) {
    this.name = value
  }
}
// second_controller.js
export default class extends Controller {
  render() {
    $(document).trigger('first_controller.state', function(firstController) {
      // first_controller のstate/dataを取得するコードをここに書く
      this.name = firstController.name
      // second_controller固有のUIをレンダリングするコードをここに書く
    })
  }
}

そうする理由

コードが成長すると、多くのコントローラが他のコントローラのデータを必要とするようになるかもしれません。イベントトリガーをいくつも書いてコントローラ同士を連携することも一応可能ですが、冗長かつ非効率です。

データを持つコントローラは、必ずしもあらゆるインスタンスでイベントをトリガーする必要が生じるとは限りません。代わりに上の方法を使えば、各コントローラがコールバックで自分自身を返すようにできます。

注意

コールバックの目的を設計で明確にしておくべきです。たとえば、この手法を乱用して別のコントローラがアクションをトリガーしまくるようなことは避ける必要があります。そのようなことをすると、「コントローラは単一のコンポーネントを扱うべき」というStimulusJSの設計が損なわれてしまいます。

しかし、何らかの形でコントローラ同士の通信を行うことが避けられない場合は、この方法でコードを整理して共通のインターフェイス(message busデザインパターンなど)を提供しましょう。

参考資料

https://rails.substack.com/p/stimulusjs-finding-out-the-state

関連記事

Better Stimulusガイド:アーキテクチャ1: アプリケーションコントローラ(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。