What is StimulusReflex? Quite popular nowadays HTML over-the-wire approach led us to the creation of frameworks and libraries which send HTML over the wire instead of using JSON. StimulusReflex is one of them.
It is new way to create reactive user interface in Ruby on Rails.
StimulusReflex extends the capabilities of Rails and Stimulus by capturing user interactions and passing them to Rails over real-time websockets. Pages are quickly re-rendered and all updates are sent to the client via CableReady.
CableReady allows to create real-time updates by triggering client-side DOM changes, events and notifications via ActionCable. Unlike Ajax, operations are not always initiated by the user other browser, for example, they can also be initiated by workers.
StimulusReflex was originally inspired by Phoenix’s LiveView (an alternative to the SPA). StimulusReflex’s goal has always been to make building modern apps with Rails the most productive and enjoyable option available. And in my opinion, this is exactly what they achieved here.
Why should we use StimulusReflex?
It’s simple, to focus on developing a product instead of introducing consistent changes in modern JavaScript. Also, StimulusReflex applications have simple, concise and clear code and integrate seamlessly with Ruby on Rails. This allows small RoR teams to do big things even without great knowledge of React, Vue or their modern JavaScript solutions.
How does StimulusReflex works?
Reflex
Reflex is a transactional UI update that takes place over a persistent open connection to the server. StimulusReflex maps requests to Reflex class. Reflex classes are in the app/reflexes
directory.
class PostReflex < ApplicationReflex
end
If we create Reflex class with a generator, we can see that our class contains this comment:
# All Reflex instances include CableReady::Broadcaster and expose the following properties:
#
# - connection – the ActionCable connection,
# - channel – the ActionCable channel,
# - request – an ActionDispatch::Request proxy for the socket connection,
# - session – the ActionDispatch::Session store for the current visitor,
# - flash – the ActionDispatch::Flash::FlashHash for the current request,
# - url – the URL of the page that triggered the reflex,
# - params – parameters from the element’s closest form (if any),
# - element – a Hash-like object that represents the HTML element that triggered the reflex,
# - signed – uses a signed Global ID to map dataset attributed to a model e.g., element.signed[:foo],
# - unsigned – uses an unsigned Global ID to map dataset attributed to a model e.g., element.unsigned[:foo],
# - cable_ready – a special cable_ready that can broadcast to the current visitor (no brackets needed),
# - reflex_id – a UUIDv4 that uniquely identifies each Reflex.
As we can see, there are few properties that can be used in our class. The most interesting at the beginning will be the element
property that contains all of the Stimulus controller’s DOM element attributes as well as other properties, like tagName
, checked
and value
.
StimulusReflex also gives us a set of callbacks to allow us to control our reflex’s processes:
- before_reflex
- around_reflex
- after_reflex
As you can see, the naming is very similar to Active Record Callbacks.
Declaring a Reflex in HTML with data attribute
The fastest way to enable Reflex actions is by using the data-reflex
attribute. The syntax follows the Stimulus format: [DOM-event]->[ReflexClass]#[action]
"="">StimulusReflex documentation. Shoutout to all people involved into the development of StimulusReflex!
In this example, the data-reflex
attribute pointed out the PostRefex
class and the increment
method on the click
event. Here we also passed data-post-id
that we can later use in the Reflex class through element.dataset[:post_id]
.
class PostsReflex < ApplicationReflex
def increment
post = Post.find(element.dataset[:post_id])
post.increment! :likes
end
end
Morphs
By default, StimulusReflex updates the entire page (Page morph). After re-processing the controller action, rendering the view template and sending the raw HTML to your browser, StimulusReflex uses the morphdom
library to do the smallest number of DOM modifications necessary to refresh your UI in just a few milliseconds.
StimulusReflex features three distinct modes of operation:
Page Morph – performs a full-page update,
Selector Morph – replaces the content of an element,
Nothing Morph – executes functions that do not update your page (for example, calling your employee).
To change our PostReflex#increment
method, we can simply use the morph
keyword and target the partial that we want to update.
def increment
post = Post.find(element.dataset[:post_id])
post.increment! :likes
morph "#posts_#{post.id}", render(partial: 'post', locals: { posts: post })
end
My thoughts
This quite a short introduction is enough to start your journey with reactive Rails using StimulusReflex. Isn’t it great to be able to create a reactive SPA app with just a few Ruby lines and no JavaScript? For me, this whole HTML over-the-wire idea is exciting, and I will definitely dig into this topic in the future. For now, I highly recommend to you StimulusReflex documentation. Shoutout to all people involved into the development of StimulusReflex!
Read more:
Why you should (probably) use Typescript
How not to kill a project with bad coding practices?
Data fetching strategies in NextJS