A great user experience can be created with Rails alone. Tools such as Russian Doll caching, UJS, Stimulus, and Turbolinks are incredibly powerful when combined. Could you build your application using these tools without introducing StimulusReflex?
It might strike you as odd that we would start by questioning whether you need this library at all. Our motivations are an extension of the question we hope more people will ask.
Instead of "Which Single Page App framework should I use?" we believe that StimulusReflex can empower people to wonder "Do we still need React, given what we now know is possible?" 🤯
There are two ways to enable StimulusReflex in your projects: use the
data-reflex attribute to declare a reflex without any code, or call the
stimulate method inside of a Stimulus controller. We can use these techniques interchangeably, and both of them trigger a server-side "Reflex action" in response to users interacting with your UI.
Let's dig into it!
This example updates the page with the latest count when the link is clicked:
app/views/pages/index.html.erb<a href="#"data-reflex="click->CounterReflex#increment"data-step="1"data-count="<%= @count.to_i %>">Increment <%= @count.to_i %></a>
We use data attributes to declaratively tell StimulusReflex to pay special attention to this anchor link. The
data-reflex attribute allows us to map an action on the client to code that will be executed on the server.
The syntax follows Stimulus format:
The other two attributes
data-count are used to pass data to the server. You can think of them as arguments.
app/reflexes/counter_reflex.rbclass CounterReflex < StimulusReflex::Reflexdef increment@count = element.dataset[:count].to_i + element.dataset[:step].to_iendend
StimulusReflex maps your requests to Reflex classes that live in your
app/reflexes folder. In this example, the
increment action is called and the count is incremented by 1. The
@count instance variable is passed to the template when it is re-rendered.
Real-world applications will benefit from additional structure and more granular control. Building on the solid foundation that Stimulus provides, we can import StimulusReflex into our Stimulus controllers and build complex functionality.
Let's build on our increment counter example by adding a Stimulus controller and manually triggering a Reflex action by calling the
Declare the appropriate data attributes in HTML.
Create a server side Reflex object with Ruby.
Create a server side Example controller with Ruby.
app/views/pages/index.html.erb<a href="#"data-controller="counter"data-action="click->counter#increment">Increment <%= @count %></a>
Here, we rely on the standard Stimulus
data-action attributes. There's no StimulusReflex-specific markup required.
connect lifecycle method fires during both the initial browser page load and after Turbolinks visits that refresh content. We tell StimulusReflex that this controller is going to be calling server-side Reflex actions by passing the Stimulus Controller instance to the
register method. This gives the controller a
stimulate method that we can call.
When the user clicks the anchor, the Stimulus event system calls the
increment method on our controller. In this example, we pass two parameters: the first one follows the format
[ServerSideClass]#[action] and informs the server which Reflex action in which Reflex class we want to trigger. Our second parameter is an optional argument that is passed to the Reflex action as a parameter.
app/reflexes/counter_reflex.rbclass CounterReflex < StimulusReflex::Reflexdef increment(step = 1)session[:count] = session[:count].to_i + stependend
Here, you can see how we accept a
step argument to our
increment Reflex action. We're also now switching to using the Rails session object to persist our values across multiple page load operations. Note that you can only provide parameters to Reflex actions by calling the
stimulate method with arguments; there is no equivalent for Reflexes declared with data attributes.
app/controllers/pages_controller.rbclass PagesController < ApplicationControllerdef index@count = session[:count].to_iendend
Finally, we set the value of the
@count instance variable in the controller action. When the page is first loaded, there will be no
session[:count] value and
@count will be
nil, which converts to an integer as 0... our initial value.
We provide a generator that performs a scaffold-like functionality for StimulusReflex. It will generate files and classes appropriate to whether you specify a singular or pluralized name for your reflex class. For example,
users are both valid and useful in different situations.
bundle exec rails generate stimulus_reflex user
This will create but not overwrite the following files: