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.
To add a reflex to your component, use the reflex method.
reflex :my_cool_reflex do
# do stuff
refresh!
end
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.
note: A reflex will not automatically re-render the component upon its completion. A component will re-render whenever the set_state or refresh! method is called.
In addition to calling reflexes, there is a rudimentary state system. You can initialize component-local state with initialize_state(obj), where obj is a hash.
You can access state with the state helper. See the code below for an example. Calling set_state will set the state,
and also re-render your component.
If you're using state add data-key="<%= key %>" to any html element using a reflex. This
lets ViewComponentReflex keep track of which state belongs to which component.
# counter_component.rb
class CounterComponent < ViewComponentReflex::Component
def initialize
initialize_state({
count: 0
})
end
reflex :increment do
set_state(count: state[:count] + 1)
end
end
# counter_component.html.erb
<div data-controller="counter">
<p><%= state[:count] %></p>
<button type="button" data-reflex="click->CounterComponentReflex#increment" data-key="<%= key %>">Click</button>
</div>
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
##
# 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)
end
##
# 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 = {})
# store the state
# this will be called twice, once with key, once with key_initial
# key_initial contains the initial, unmodified state.
# it should be used in reconcile_state to decide whether or not
# to re-initialize the state
end
##
# request - a rails request object
# key - a unique string that identifies the component instance
# new_state - a hash containing the component state
def self.reconcile_state(request, key, new_state)
# The passed state should always match the initial state of the component
# if it doesn't, we need to reset the state to the passed value.
#
# This handles cases where your initialize_state param computes some value that changes
# initialize_state({ transaction: @customer.transactions.first })
# if you delete the first transaction, that ^ is no longer valid. We need to update 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