Lightning fast reactive action with Stimulus Reflex partial morphs

Stimulus reflex is an awesome way to build reactive single-page-like applications with Ruby on Rails, with minimal Javascript.

The newest update v 3.3.0 introduces partial morphs, that don’t go through the controller action anymore, and it allows us to make reflexes lightning fast.

How does a reflex action work? (simplified)

So this gives us a lot of convenience as we reuse all the logic of the original controller action that rendered a page initially. However this convenience also means that every reflex can only be about as fast as the controller action it performs.

Introducing morph :selector

This release will introduce different morph modes that allow you to skip the controller action and instead render a partial, a view_component or a string, that you then morph into the page.

Let us look at an example:

In my application I have a timeline with 21 days where I can add orders to those days. Executing the controller action and rendering takes around 180ms, which is not horrible, but definitely not great.

Timeline with orders

To delete an item in the timeline we can have a simple reflex:

timeline_reflex.rb

def delete
  ScheduledOrder.destroy(element.dataset[:scheduled-order-id])
end

which is triggered from a simple button with the right data attributes

<button data-reflex="click->My::TimelineReflex#delete" data-scheduled-order-id="<%= order.id %>">

So simple, so slim, so convenient.

But every delete reflex action, will include those 180ms to execute the controller action, meh.

Speeding up with with partial morph.

Now we can leverage only doing a partial update.

timeline_reflex.rb:

def delete
  # we delete
  ScheduledOrder.destroy(element.dataset[:order_id])

  # we get all the data we need to render the component
  @date = element.dataset[:date]
  @pauses = current_user.pauses
  @scheduled_orders = current_user.scheduled_orders.where(date: @date)

  # we call morph with a selector and pass the rendered component into it.
  morph "##{day_dom_id}", ApplicationController.render(My::TimelineDayComponent.new(day: @date, scheduled_orders: @scheduled_orders, pauses: @pauses))
end

Now instead of doing all the controller action stuff, and rendering 21 days components. We just render one day component. So our time to execute the reflex action goes down from 180ms to about 30ms. 30 milliseconds!

With partial morphs we get SPA-speed interactions, without ever having to handle client side state. I love it!


Originally posted on dev.to