Stimulus 是一個簡單的 JavaScript 框架, 它最主要的特色是可以使用你現有的 HTML 去賦予他們生命 (類似於 Angular 1.0, 但是簡單許多).

在透過將試作型討戰網上的大大小小以 Stimulus 改寫後, 獲得了許多零散的心得. 若你對 Stimulus 有興趣, 但不知道是否該引入到目前的專案的話, 這篇筆記或許可以幫助到你.

專案背景簡介

  • 試作型討戰網是一個 Ruby on Rails 網頁應用程式.
  • 它不是一個 Single Page App, 也沒有在所有的地方都使用 React, 使用了 Turbolinks.
  • 前端使用了 React 與 Redux 建構那些比較複雜的地方.

Stimulus 的吸引力

  • 可以直接使用 Rails app 的 view, 不需要維護兩份.
  • 可以用任何自己喜歡方式操作 HTML, 例如可以使用 insertAdjacentHTML, 甚至可以直接使用 innerHTML.
  • Stimulus 透過使用 Mutation Observer 監視任何變更, 會自動綁定任何擁有 controller 的元素, 我甚至能做到在做某些事情後執行 el.setAttribute('data-controller', controllers) 去追加 controller.
  • 可以直接操作 DOM 在某些場合很方便, 這點在 React 挺麻煩的…
  • 喜歡某個 jQuery plugin 但它沒有 React 版本, 你可以直接使用, 沒有額外煩惱.
  • 如果你喜歡 UJS, 那你也一定會喜歡 Stimulus.
  • 學習與開發成本非常低, 你是公司唯一的網頁開發者嗎? 這會是你的好朋友, 而且不會有任何 React 的前端開發者嘗試阻止你.

Stimulus 的麻煩點

  • 直接操作 DOM 是一件很痛苦的事情, 不過這方面可以用 jQuery 讓自己少點痛苦. 也可以嘗試使用 Cash
  • 與其他 controller 溝通不太方便, 它提供了 application.getControllerForElementAndIdentifier 方法, 但這名字長到怎麼看都不是鼓勵使用者頻繁使用的方法.
  • 另一個與其他 controller 溝通的方法是觸發 CustomEvent.
  • 如果像我一樣不喜歡把所有的功能混一起寫, 那你可能會在 HTML 中看到大量的 data-controller data-action data-target 地獄.

如何與 React 元件溝通?

如果使用 Redux, 那最好的方式應該是使用 store.dispatch(action) 去更新 store, 讓它去影響 React 元件.

在 React 中使用 Stimulus controller?

我覺得可以, 但我還沒嘗試過, 如果只是做一些只操作某些 DOM 屬性的功能應該很適合吧.

像最後面附上的這個範例.

使用 Stimulus 完全取代 React?

可行, 但我認為他們的強項不同, 何時該用哪個完全是看情況而定.

範例

https://gist.github.com/ayamomiji/e755bb1b7f477840e4d66b8a2ba7acea

這是一個智慧捲動的範例: 在新元素被插入前, 如果捲軸已經捲動到最底下了, 就在插入元素後捲動到最後.

Stimulus 並不鼓勵與其他 controller 頻繁互動, 但我覺得在這個例子, 與 parent controller 溝通很方便, 因此寫了這個方法, 並且要求自己儘量最小幅度的使用它.

export function getParentController(controller, identifier) {
  const application = controller.application
  let element = controller.element
  do {
    let foundController =
      application.getControllerForElementAndIdentifier(element, identifier)
    if (foundController) {
      return foundController
    }
  } while (element = element.parentElement)
}