ViewComponentReflex

ViewComponentReflex allows you to write reflexes right in your view component code.

Usage

You can add reflexes to your component by adding inheriting from ViewComponentReflex::Component.

This will act as if you created a reflex with the method my_cool_stuff. To call this reflex, add data-reflex="click->MyComponentReflex#my_cool_reflex", just like you're using stimulus reflex.

ViewComponentReflex will maintain your component's instance variables between renders. You need to include data-key=<%= key %> on your root element, as well as any element that stimulates a reflex. ViewComponent is inherently state-less, so the key is used to reconcile state to its respective component.

Example

# counter_component.rb
class CounterComponent < ViewComponentReflex::Component
  def initialize
    @count = 0
  end

  def increment
    @count += 1
  end
end
# counter_component.html.erb
<%= component_controller do %>
    <p><%= @count %></p>
    <button type="button" data-reflex="click->CounterComponentReflex#increment" data-key="<%= key %>">Click</button>
<% end %>

Collections

In order to reconcile state to components in collections, you can specify a collection_key method that returns some value unique to that component.

class TodoComponent < ViewComponentReflex::Component
  def initialize(todo:)
    @todo = todo
  end

  def collection_key
    @todo.id
  end
end
#
<%= render(TodoComponent.with_collection(Todo.all)) %>

Custom State Adapters

ViewComponentReflex uses session for its state by default. To change this, add an initializer to config/initializers/view_component_reflex.rb.

ViewComponentReflex.configure do |config|
  config.state_adapter = YourAdapter
end

YourAdapter should implement

class YourAdapter
  ##
  # request - a rails request object
  # key - a unique string that identifies the component instance
  def self.state(request, key)
    # Return state for a given key
  end

  ##
  # set_state is used to modify the state. It accepts a reflex, which gives you
  # access to the request, as well as the controller and other useful objects. 
  #
  # reflex - The reflex instance that's trying to set the state
  # key - a unique string that identifies the component
  # new_state - the new state to set
  def self.set_state(reflex, key, new_state)
    # update the state
  end


  ##
  # store_state is used to replace the state entirely. It only accepts
  # a request object, rather than a reflex because it's called from the component's 
  # side with the component's instance variables.
  #
  # request - a rails request object
  # key - a unique string that identifies the component instance
  # new_state - a hash containing the component state
  def self.store_state(request, key, new_state = {})
    # replace the state
  end
end

Installation

Add this line to your application's Gemfile:

gem 'view_component_reflex'

And then execute:

$ bundle

Or install it yourself as:

$ gem install view_component_reflex

License

The gem is available as open source under the terms of the MIT License.

Caveats

State uses session to maintain state as of right now. It also assumes your component view is written with the file extension .html.erb