【Rails7】Stimulus入門! | 概要 ~ 使い方まで詳しく解説

はじめに

この記事の概要

こんにちは、株式会社TOKOSのツキヤです!
今回は、RailsでJavaScriptを扱う際にはスタンダードとなりつつあるStimulusについての簡単な説明から、使い方まで解説します!
個人的には、少ないJavaScriptの記述量でアニメーションやDOM操作が可能となるのでかなりオススメの技術です😎
あまり知らなかった人も、この機会にサラッと学んでみましょう✨

対象読者

  • Stimulusが何なのか知りたい人
  • RailsでDOM操作を行いたい人

Stimulusとは?

Hotwireについて

Stimulusについて解説するために、まずはHotwireという技術について説明します!
Hotwireをひとことで説明すると、「JavaScriptをあんまり書かずに今どきのリッチなアプリケーションを作る」技術です!

今どきのアプリケーションは、様々な動作やアニメーションを駆使してユーザーの使いやすさを上げようとしているものばかりですね💪
ユーザーにとってはどんどん便利になって嬉しいかと思いますが、開発者はそれに比例してどんどん仕事の量が増えてしまいます、、😢
更に、そういったフロントエンドの記述は基本的にJavaScriptで書きますが、RailsエンジニアはJavaScriptをそこまで得意としていない人もいます😨

そこで、Railsはより少ない(JavaScriptの)記述で今どきのアプリケーションを作りたいという方向に舵を切り、その結果としてHotwireという技術が出来上がりました🥳

Hotwireは大きくは「Turbo + Stimulus」という要素で構成されています。

ツキヤ
ツキヤ

Turboについては今回は解説は省略します🙏

Stimulusについて

Hotwireの概要を説明したので、いよいよStimulusの解説に移ります!
Stimulusの主な仕事については、いわゆるDOM操作をさせるものとなります!

  • ボタンが押された時に色を変更
  • ハンバーガーメニューの処理
  • モーダル画面の表示

上記のように、URLの変更無しでの動作を簡単に記述できます😎
もちろんこれ意外にもJavaScriptで行いたい動作もできます!

Stimulusの実態としては、JavaScriptのライブラリです。なので、Rails以外でも使うことはもちろん可能です!
ですが、Railsで使う場合は“stimulus-rails”というgemがあります。これはStimulusを使いやすくするためのgemで、更に実装を助けてくれるので基本はRails上で使うことがオススメです!

他のJSライブラリとの違い

最近はフロントエンドはVue, Reactが使われる場合がほとんどかと思います。
これらのライブラリと比べたときのメリットは「記述が少ない」「環境構築が不要」とうことかと思います!

「記述が少ない」ということについては先程からずっと書いていますよね!
こちらについては後ほど体感してもらいますのでお楽しみに😎

「環境構築が不要」ということについてもかなりメリットかと思います!
通常Vue(Nuxt.js)やReact(Next.js)をフロントエンドと使用する場合はフロントエンドの環境構築やメンテナンスも必要になります。
このコストが結構大きいですが、Stimulusで実装する場合はかなり楽に導入ができます✨
こちらに関しても次の章で具体的に体感してもらいましょう😎

導入方法

導入方法

では早速Stimulusを導入します!

…と言いましたが、Rails7で$ rails newをする際に自動でインストールされているかと思います💪

# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"

初期時点でちゃんと“stimulus-rails”が入っていました✨

ツキヤ
ツキヤ

JSの管理にWebpackを使っている場合は、package.jsonに“@hotwired/stimulus”が入っているよ!

後から導入したい場合は、上記の“stimulus-rails”(+ “@hotwired/stimulus”)をインストールすることで導入可能です!

ファイル構成

次に、Stimulusの記述するファイルの場所等について説明します!

起点となるファイルは、app/javascript/application.jsです!

// Entry point for the build script in your package.json
import "@hotwired/turbo-rails"
import "./controllers"

簡単に解説すると、必要なライブラリそのものと実際に自分で書くファイル群を集めるapp/javascript/controllersディレクトリ内のindex.jsを読み込んでいます!
このファイルは基本的には自分では触らないかと思います!

続いて、読み込み先のapp/javascript/controllers/index.jsを確認します!

// This file is auto-generated by ./bin/rails stimulus:manifest:update
// Run that command whenever you add a new controller or create them with
// ./bin/rails generate stimulus controllerName

import { application } from "./application"

import HelloController from "./hello_controller"
application.register("hello", HelloController)

5行目で、更に同じディレクトリ内のapplication.jsを読み込んでいます。細かくは割愛しますが、application.js内の記述によってやっとStimulusを起動することになります✨

7,8行目の記述については、最初のサンプルファイルとなるhello_controller.jsを読み込んでからStimulusの動作として登録しています。
この記述については、$ rails generate stimulus 〇〇コマンドを打ってファイルを作成する度に自動で追記されます!
なので、こちらのファイルも基本的には自分で追記しません

使い方・記述方法

Stimulusのファイル作成 ~ 実行

それでは、ここから実際にStimulusのファイルを作成して実際にブラウザで動作を確認するところまで行ってみます!
今回実装する機能は、Stimulusの公式サイトと同じ機能にします!
具体的には、inputタグの中に文字を適当に書いてボタンを押したら、”Hello 〇〇”というテキストをspanタグに生成するものです!
動作を確認したい方は下記リンクで見てみてください。

それでは、必要なファイルを作成するために、ターミナルに下記コマンドを打ち込んで下さい!

rails generate stimulus issen

これで、
・「app/javascript/controllers/index.jsへの追記」
・「app/javascript/controllers/issen_controller.jsの作成」
が行われました。順に確認してみます!

ツキヤ
ツキヤ

「issen」という文字はファイル名に使われる自由な文字列だよ!
実際に開発をする時は意味を持たせるような名前が良いね!

// This file is auto-generated by ./bin/rails stimulus:manifest:update
// Run that command whenever you add a new controller or create them with
// ./bin/rails generate stimulus controllerName

import { application } from "./application"

import HelloController from "./hello_controller"
application.register("hello", HelloController)

import IssenController from "./issen_controller"
application.register("issen", IssenController)

index.jsには、issen_controller.jsを読み込む処理が追加されています!

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="issen"
export default class extends Controller {
  connect() {
  }
}

issen_controller.jsには、Stimulusの雛形となる記述があります!
このファイルを記述していくことで今回の機能を実装します!

JavaScriptの記述

ここからは、issen_controller.jsと適当なindex.html.erbファイルに追記をしていきます!

index.html.erb

Stimulusの公式ページを適当なところにペーストしてみます!
(お好みでCSSをあてて下さい)

<!--HTML from anywhere-->
<div data-controller="hello">
  <input data-hello-target="name" type="text">

  <button data-action="click->hello#greet">
    Greet
  </button>

  <span data-hello-target="output">
  </span>
</div>

今回は、controllerファイルの名前が”issen”なので、”hello”となっている部分を全て”issen”にしてみます!

<!--HTML from anywhere-->
<div data-controller="issen">
  <input data-issen-target="name" type="text">

  <button data-action="click->issen#greet">
    Greet
  </button>

  <span data-issen-target="output">
  </span>
</div>

合計4箇所を変更しました!
2行目のdata-controller=”issen”部分で、このファイルのこの(div)タグ内でissen_controller.jsを使います という意味になります!
その他の部分は追って解説します!

issen_controller.js

まずは、ちゃんとこのissen_controller.jsindex.html.erbに読み込まれているかを確認します!
次のように追記して下さい

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="issen"
export default class extends Controller {
  connect() {
    console.log("Hello, I'm issen_controller.js!!!")
  }
}

connect()メソッド内の記述は、このcontrollerが読み込まれた際に実行されます!
そこでconsole.logメソッドを仕込んで実際にブラウザのConsoleに”Hello, I’m issen_controller.js!!!”と表示されるか確認します。

index.html.erbのページをリロードしてみると、

ちゃんと表示されました!
これで上手く動いてくれることが確認できました💪

続いて、機能実装のための記述を追加していきます。
この記述についても、Stimulusの公式ページの内容をベースに追記します!

import { Controller } from "@hotwired/stimulus";

// Connects to data-controller="issen"
export default class extends Controller {
  static targets = ["name", "output"];

  connect() {
    console.log("Hello, I'm issen_controller.js!!!");
  }

  greet() {
    this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`;
  }
}

これで準備完了です!
ブラウザで実際に触ってみましょう!

無事同じ動作をしてくれました✨✨

解説

それでは、なぜこのような動作をするのかの解説をします!
大事なのは、「要素の取得」「動作の発火」です!

要素の取得

data属性の記述によって、StimulusはHTMLのinputタグやspanタグを取得しています!
今回の場合、inputタグはdata-issen-target=”name”、spanタグはdata-issen-target=”output”とかかれていますよね。
この記述でissen_controller.jsname,outputという変数に格納されるということです!
issen_controller.js側にstatic targets = [“name”, “output”]という記述をする必要もありますので忘れずに書きましょう!

これで要素をJS側でthis.outputTargetthis.nameTargetというような形で使用することができます!

ツキヤ
ツキヤ

変数名によって書き換える場所がやや分かりづらいので注意してください!
data-○○-target=”××”の時、○○_controller.jsのthis.××Targetになるよ!

動作の発火

spanタグの中身を書き換えるロジックがgreet()メソッドになります!

// 略
  greet() {
    this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!`;
  }
}

このメソッドは「spanタグの中身のテキストを”Hello + inputタグの中身の文字列”に変更して」という内容なりますね!

ではボタンを押した時にどうやってこのgreet()メソッドを発火させているかというと、HTML側のbuttonタグ内のdata-action=”click->issen#greet”という記述です!
この記述で、「この要素をクリックした時に、issen_controller.jsgreet()メソッドを実行して下さい」という内容になります!

ツキヤ
ツキヤ

JavaScriptが少し分かる人向けに言うと、click部分はeventになります!
なのでfocusやmouseover等も使えるよ!

終わりに

今回はStimulusの概要の説明から、簡単な使い方まで説明しました!
実際のJavaScriptの記述は数行でしたが、ちゃんとDOM操作ができましたね、すごい✨

現状はまだまだ参考になる記事があまりないかと思いますが、少し勉強するだけでリッチなUIを作ることができるので頑張ってキャッチアップしましょう!
Railsの勉強をしたい方はこの本が参考になるかと思いますので興味がある方は是非読んで見て下さい🙇‍♂️

次回は細かい命名規則等に触れながら解説予定ですのでお楽しみに😎