stimulus

 stimulus

ginza.rb#64 でstimulusを紹介したときに使った資料です

https://ginzarb.doorkeeper.jp/events/81390

6ac7c50770603b53964d44db373e8e48?s=128

Shinichi Maeshima

October 16, 2018
Tweet

Transcript

  1. stimulus — ginza.rb#64 — @willnet

  2. とは — Stimulus: A modest JavaScript framework for the HTML

    you already have. — Basecamp製のJSフレームワーク — 現在のバージョン1.1.0(2018/8/23)
  3. 試用 — webpackなどでプリコンパイルするのを推奨 — cloneしてサッと試せるお試し用リポジトリがある — stimulusjs/stimulus-starter: A humble blank

    slate for a modest JavaScript framework — rails使いなら rails new --webpack=stimulus yourappname でも環境作れるのでそっちでもよさそう — 公式チュートリアル的なのがあるので、それを見ながら手 を動かすとよいのでは
  4. 特徴 — react や vue.js とは志向がぜんぜん違う — データバインディングとかVirtual DOMとか、なにそれ 美味しいの?って感じ

    — あくまでサーバが吐くHTMLと仲良くするためのフレーム ワーク — turbolinks friendly — サーバサイドの人が片手間でやるフロントエンドで、 vue.jsなどを導入する余裕がない…みたいなときに導入す るのが良いのでは、という気がする — 現行のjsを整理するために使う
  5. どういうときに便利そうか — 通常RailsのJSはファイルごとにそれっぽく関数やイベント 登録などが整理されるけれど、特に強制力はない — なのでフラットにイベントが登録されたり、関数が登録 されたりする可能性がある — 例えば users.js

    に user とあまり関係ない関数が 登録されたりする — DOMのclass属性とjsが紐付けられる事が多いけど、cssのた めに使うclassなのかjsで使うclassなのか分かりづらい — stimulusを使うとDOMに controller, target, action を割 り振ることができ、規約によって関数群を整理できる、と いうのがstimulusのキモの一つ(だと思う)
  6. どういうときに便利そうか — turbolinksを使っているときに、特定のページでだけ実行 したい処理を書くのが面倒 — 特定のDOMがあるかチェックして、なかったらreturnす る、みたいな処理を毎回書く — だるい

  7. こういうやつ $(document).on('ready turbolinks:load', () => { const target = $('.condition_transfer_on')

    if (target.length === 0) { return } // .condition_transfer_on͕͋ͬͨ৔߹ͷॲཧ — stimulusを使うと「controllerがページ表示されたタイミ ング(connectされたタイミング)でなにか処理を実行する」 みたいなのが楽にかける
  8. controller, target, action とは stimulus 公式のトップページを見ながら解説するとわかりや すそう Stimulus: A modest

    JavaScript framework for the HTML you already have.
  9. HTMLのコード <div data-controller="hello"> <input data-target="hello.name" type="text"> <button data-action="click->hello#greet"> Greet </button>

    <span data-target="hello.output"> </span> </div>
  10. jsのコード import { Controller } from "stimulus" export default class

    extends Controller { static targets = [ "name", "output" ] greet() { this.outputTarget.textContent = `Hello, ${this.nameTarget.value}!` } }
  11. 結果 名前を入力してGreet!をクリックすると、右側に名前を含んだ 文字列が出力される

  12. HTMLとjsの対応付け — data-controllerの値とjsファイル名が紐付いている — data-actionの値とメソッドが紐付いている — data-targetの値とstatic targets = []

    で定義された値が 紐付いている — static targets = ["name"] などとすると、 this.nameTarget でDOMの要素を扱うことができるよう になる
  13. stimulusの大まかな機能は これだけ

  14. 完?

  15. それぞれもうちょっと詳し く

  16. controller — html中のdata-controllerに合わせて、紐付いた名前の controllerをインスタンス化し、DOMと紐づけてくれる — 例えば<div data-controller="hello"> であれば hello-controller.jsが自動的に読み込まれる —

    ファイル名にアンダースコアを使うこともできる — date_picker_controller.js -> date-picker — 参考: https://stimulusjs.org/handbook/ installing#controller-filenames-map-to- identifiers
  17. 複数のコントローラを一つのDOMに紐付けること ができる <div data-controller="clipboard list-item"></div>

  18. コントローラを複数のDOMに紐付けることができ る <ul> <li data-controller="list-item">One</li> <li data-controller="list-item">Two</li> <li data-controller="list-item">Three</li> </ul>

    li要素それぞれに、別々のコントローラのインスタンスが割り 当てられる
  19. action <div data-controller="gallery"> <button data-action="click->gallery#next">…</button> </div> — イベントの名前(click) — コントローラ名(garraly)

    — アクション名(next) をそれぞれ指定する
  20. eventオブジェクト actionとして定義されたメソッドに、eventオブジェクトが引 数として渡ってくる import { Controller } from "stimulus" export

    default class extends Controller { next(event) { // … } }
  21. eventオブジェクト — event.type でなんのイベントなのかが返る(例: 'click') — event.targetでどのDOM発祥なのか返る — event.currentTargetでイベントリスナが登録されている DOMが返る

  22. イベントの名前 — DOM要素によっては省略できる — 例えばa要素ならclickがデフォルトで省略可能

  23. 同じDOMに複数イベント登録できる <input type="text" data-action="focus->field#highlight input->search#update">

  24. target Action以外のDOMとjsの紐づけはtargetでやる

  25. html <div data-controller="search"> <input type="text" data-target="search.query"> <div data-target="search.errorMessage"></div> <div data-target="search.results"></div>

    </div> controller໊.target໊ で指定する
  26. js import { Controller } from "stimulus" export default class

    extends Controller { static targets = [ "query", "errorMessage", "results" ] // … } — statis targets に配列でtargetになる要素の名前を渡す — すると後述のプロパティが生える
  27. プロパティ 例えばqueryという名前のtargetを指定すると次のプロパティ が自動で生える — this.queryTarget — 最初にマッチしたDOMが返る — this.queriesTarget —

    マッチしたDOMが全部返る — this.hasQueryTarget — DOMが存在しているのかbooleanで返る
  28. 一つのDOMに複数のtargetを指定できる <form data-controller="search checkbox"> <input type="checkbox" data-target="search.projects checkbox.input"> <input type="checkbox"

    data-target="search.messages checkbox.input"> … </form>
  29. Data Maps <div data-controller="content-loader" data-content-loader-url="/messages"> </div> — 状態をどこで持つのか、という話 — 他のjsフレームワークはjsで持つけど、stimulusjsはDOMで

    持つ — html側からjs(その逆も)になにかデータを渡すとき、data- ίϯτϩʔϥ໊-σʔλ໊で渡すというのがstimulusjsでの お作法
  30. js // controllers/content_loader_controller.js import { Controller } from "stimulus" export

    default class extends Controller { connect() { fetch(this.data.get("url")).then(/* … */) } } — this.data.get("url")でdata-content-loader-urlの値を取 得できる
  31. その他のメソッド — this.data.set(key, value) — DOMの方にデータを設定する — this.data.has(key) — booleanで、そのkeyのdataが存在しているのか返す

    — this.data.delete(key) — keyに紐づくdataを消す
  32. 注意点 — dataはNumberでアサインしても、getするとStringで返って くる — とくに型変換とかはしてないもよう this.data.set("count", 1) this.data.get("count") //

    "1"
  33. Lifecycle Callback controllerのインスタンスがDOMに割り当てられたときなどに hookしてメソッド実行をさせることができる import { Controller } from "stimulus"

    export default class extends Controller { connect() { // … } }
  34. メソッド — initialize — controllerのインスタンスが作られたタイミング — connect — DOMに紐付いたタイミング —

    ドキュメント上にdata-controllerを持つDOMが現れたら connectされる — disconnect — DOMとの紐づけがなくなったタイミング — data-controllerを持つDOMが消されたり、data- controller属性自体が消されたりしたらdisconnect
  35. DOMが存在する/しないで自動でcontrollerが紐付けられるというのが — turbolinksフレンドリーってことっぽい?

  36. インスタンスは使い回される — disconnectしたあとにまたconnectされるケースでは、イン スタンスが使い回される — つまりconnectやdisconnectは複数回呼ばれる可能性が ある

  37. まとめ

  38. メリット — 学習コストがめっちゃ低い — 一日あれば使えるようになるのでは? — vannilajsやjQueryで作っているサービスから移行しやすい — 試してみた結果やめたくなった場合も比較的やめやすそう

  39. デメリット — vannilajsから移行しても「単にメソッドやイベントを整理 した」以上にはならない — マジカルな何かですごいことになる、ということはない — できることが限定的 — SPAとか無理(そういうのはturbolinks使って擬似的にや

    ればいいじゃん、という考え) — JSON APIを叩いて云々、とかは考えてない — クライアントサイドでDOMを組み立てる、なんて大変で しょ?全部HTMLでやればいいんだよ
  40. 以上