diff --git a/lib/react/rails.rb b/lib/react/rails.rb index 59b6bd582..2c2fabbfd 100644 --- a/lib/react/rails.rb +++ b/lib/react/rails.rb @@ -2,3 +2,4 @@ require 'react/rails/engine' require 'react/rails/railtie' require 'react/rails/view_helper' +require 'react/rails/controller_renderer' diff --git a/lib/react/rails/controller_renderer.rb b/lib/react/rails/controller_renderer.rb new file mode 100644 index 000000000..65d0c2453 --- /dev/null +++ b/lib/react/rails/controller_renderer.rb @@ -0,0 +1,17 @@ +class React::Rails::ControllerRenderer + include React::Rails::ViewHelper + include ActionView::Helpers::TagHelper + include ActionView::Helpers::TextHelper + + attr_accessor :output_buffer + + def self.call(*args, &block) + new.call(*args, &block) + end + + def call(name, options, &block) + props = options.fetch(:props, {}) + options = options.slice(:data, :tag).merge(prerender: true) + react_component(name, props, options, &block) + end +end diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index e372f4af3..47ffcfed6 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -32,6 +32,14 @@ class Railtie < ::Rails::Railtie end end + initializer "react_rails.add_component_renderer", group: :all do |app| + ActionController::Renderers.add :component do |component_name, options| + html = ::React::Rails::ControllerRenderer.call(component_name, options) + render_options = options.merge(inline: html) + render(render_options) + end + end + initializer "react_rails.bust_cache", group: :all do |app| asset_variant = React::Rails::AssetVariant.new({ variant: app.config.react.variant, diff --git a/test/dummy/app/controllers/server_controller.rb b/test/dummy/app/controllers/server_controller.rb index 48f4f9757..ff14c4437 100644 --- a/test/dummy/app/controllers/server_controller.rb +++ b/test/dummy/app/controllers/server_controller.rb @@ -14,4 +14,8 @@ def console_example_suppressed React::ServerRendering.reset_pool @todos = %w{todo1 todo2 todo3} end + + def inline_component + render component: 'TodoList', props: { todos: [{todo: 'Render this inline'}] }, tag: 'span' + end end diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index f8e5775f1..1f4b4a11c 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -4,6 +4,7 @@ collection do get :console_example get :console_example_suppressed + get :inline_component end end end diff --git a/test/server_rendered_html_test.rb b/test/server_rendered_html_test.rb index 09fb7eb5c..33355c9e1 100644 --- a/test/server_rendered_html_test.rb +++ b/test/server_rendered_html_test.rb @@ -51,4 +51,13 @@ def wait_to_ensure_asset_pipeline_detects_changes assert_no_match(/console.warn/, response.body) assert_no_match(/console.error/, response.body) end + + test 'react inline component rendering' do + get '/server/inline_component' + assert_match(//, response.body) + # make sure that the layout is rendered with the component + assert_match(/Dummy<\/title>/, response.body) + end end