hyper-react
hyper-react copied to clipboard
need way to dynamically mount components (i.e. after ajax calls)
require 'jquery'
require 'opal-jquery'
module Hyperloop
def self.mount_all
Element['[data-hyperloop-mount]'].each do |mount_point|
component_name = mount_point.attr('data-hyperloop-mount')
component = nil
begin
component = Object.const_get(component_name)
rescue
message = "Could not find Component class named #{component_name}"
`console.error(message)`
next
end
params = Hash[*mount_point.data.collect do |name, value|
[name.underscore, value] unless name == 'hyperloopMount'
end.compact.flatten(1)]
React.render(React.create_element(component, params), mount_point)
end
end
%x{
window.hyperloop_mount_all = function() {
#{Hyperloop.mount_all}
}
}
end
From opal you can call Hyperloop.mount_all or from js land its hyperloop_mount_all()
It will find all components with the data-hyperloop-mount data attribute, and the name of the component will be the attribute value. For example
<DIV data-hyperloop-mount='MyBigComponent' data-param1='some data'>
</DIV>
will mount MyBigComponent at the DIV and pass it 'some data' as param1
already there:
React::Test::Utils.render_component_into_document(MyComponent, args)
maybe needs a better name
actually, its built into react-rails, and works with the <% react_component ...%> helper!
we can make it a bit nicer like this:
#jquery-mounter.rb
require 'jquery'
require 'opal-jquery'
%x{
(function ( $ ) {
$.fn.mount_components = function() {
this.each(function(e) { ReactRailsUJS.mountComponents(e[0]) })
return this;
}
}( jQuery ));
}
Element.expose :mount_components
Now we can add the components to the view using <%= react_component ... %> and mount them by doing a dom query, then calling mount_components.
Typical in JS:
// fetch.js.erb
$('#target_div').html("<%= escape_javascript(render partial: 'fetch') %>").mount_components();
// fetch.erb contains our html code including 1 or more component mount points
In Ruby
Element['body'].mount_components # mount everything!