From 3df85b0aa862cf883176e4a35fe6038bc75cb026 Mon Sep 17 00:00:00 2001 From: blackanger Date: Sun, 22 Nov 2015 16:31:11 +0800 Subject: [PATCH 1/4] Snake-Case key to Camel-Case key for props when server render --- lib/react/server_rendering/sprockets_renderer.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/react/server_rendering/sprockets_renderer.rb b/lib/react/server_rendering/sprockets_renderer.rb index 8d6940a8e..f961c632a 100644 --- a/lib/react/server_rendering/sprockets_renderer.rb +++ b/lib/react/server_rendering/sprockets_renderer.rb @@ -26,7 +26,7 @@ def render(component_name, props, prerender_options) end if !props.is_a?(String) - props = props.to_json + props = camelize_props_key(props).to_json end super(component_name, props, {render_function: react_render_method}) @@ -36,6 +36,18 @@ def after_render(component_name, props, prerender_options) @replay_console ? CONSOLE_REPLAY : "" end + def camelize_props_key(props) + return props unless props.is_a?(Hash) + props.inject({}) do |h, (k,v)| + k = k.to_s.camelize(:lower) + if v.is_a?(Hash) + h[k] = camelize_props_key(v); h + else + h[k] = v; h + end + end + end + # Reimplement console methods for replaying on the client CONSOLE_POLYFILL = <<-JS var console = { history: [] }; From 7a65962d2adb31a4a8c417d05133ee44c56a4c89 Mon Sep 17 00:00:00 2001 From: blackanger Date: Sun, 22 Nov 2015 17:50:48 +0800 Subject: [PATCH 2/4] Snake-Case key to Camel-Case key for props when server render --- lib/react/server_rendering/sprockets_renderer.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/react/server_rendering/sprockets_renderer.rb b/lib/react/server_rendering/sprockets_renderer.rb index f961c632a..f4a70724f 100644 --- a/lib/react/server_rendering/sprockets_renderer.rb +++ b/lib/react/server_rendering/sprockets_renderer.rb @@ -39,12 +39,7 @@ def after_render(component_name, props, prerender_options) def camelize_props_key(props) return props unless props.is_a?(Hash) props.inject({}) do |h, (k,v)| - k = k.to_s.camelize(:lower) - if v.is_a?(Hash) - h[k] = camelize_props_key(v); h - else - h[k] = v; h - end + h[k.to_s.camelize(:lower)] = v.is_a?(Hash) ? camelize_props_key(v) : v; h end end From 517c2f694567d4474624da0bfa34505684947f58 Mon Sep 17 00:00:00 2001 From: blackanger Date: Sun, 22 Nov 2015 17:58:32 +0800 Subject: [PATCH 3/4] Snake-Case key to Camel-Case key for props when server render --- lib/react/rails/component_mount.rb | 12 +++++++++++- lib/react/server_rendering/sprockets_renderer.rb | 9 +-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/react/rails/component_mount.rb b/lib/react/rails/component_mount.rb index 9b8f1db44..80ab6b2a2 100644 --- a/lib/react/rails/component_mount.rb +++ b/lib/react/rails/component_mount.rb @@ -23,7 +23,8 @@ def teardown(env) # on the client. def react_component(name, props = {}, options = {}, &block) options = {:tag => options} if options.is_a?(Symbol) - + props = camelize_props_key(props) + prerender_options = options[:prerender] if prerender_options block = Proc.new{ concat React::ServerRendering.render(name, props, prerender_options) } @@ -41,6 +42,15 @@ def react_component(name, props = {}, options = {}, &block) content_tag(html_tag, '', html_options, &block) end + + private + + def camelize_props_key(props) + return props unless props.is_a?(Hash) + props.inject({}) do |h, (k,v)| + h[k.to_s.camelize(:lower)] = v.is_a?(Hash) ? camelize_props_key(v) : v; h + end + end end end end diff --git a/lib/react/server_rendering/sprockets_renderer.rb b/lib/react/server_rendering/sprockets_renderer.rb index f4a70724f..8d6940a8e 100644 --- a/lib/react/server_rendering/sprockets_renderer.rb +++ b/lib/react/server_rendering/sprockets_renderer.rb @@ -26,7 +26,7 @@ def render(component_name, props, prerender_options) end if !props.is_a?(String) - props = camelize_props_key(props).to_json + props = props.to_json end super(component_name, props, {render_function: react_render_method}) @@ -36,13 +36,6 @@ def after_render(component_name, props, prerender_options) @replay_console ? CONSOLE_REPLAY : "" end - def camelize_props_key(props) - return props unless props.is_a?(Hash) - props.inject({}) do |h, (k,v)| - h[k.to_s.camelize(:lower)] = v.is_a?(Hash) ? camelize_props_key(v) : v; h - end - end - # Reimplement console methods for replaying on the client CONSOLE_POLYFILL = <<-JS var console = { history: [] }; From 1bf354e40bb3ffce3b7dba63e2230b8090a594be Mon Sep 17 00:00:00 2001 From: blackanger Date: Wed, 25 Nov 2015 22:19:13 +0800 Subject: [PATCH 4/4] add config.react.camelize_props --- README.md | 8 ++++++++ lib/react/rails/component_mount.rb | 5 +++-- lib/react/rails/railtie.rb | 3 +++ test/react/rails/component_mount_test.rb | 10 ++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 45b16b539..fcfbc8a0f 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,14 @@ end - On MRI, you'll get a deadlock with `pool_size` > 1 - If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering. +You can configure camelize_props option and pass props with an underscored hash from rails but get a camelized hash in jsx : + +```ruby +MyApp::Application.configure do + config.react.camelize_props = true #default false +end +``` + ### Rendering components instead of views Components can also be prerendered directly from a controller action with the custom `component` renderer. For example: diff --git a/lib/react/rails/component_mount.rb b/lib/react/rails/component_mount.rb index 80ab6b2a2..cb4919bb6 100644 --- a/lib/react/rails/component_mount.rb +++ b/lib/react/rails/component_mount.rb @@ -9,6 +9,7 @@ class ComponentMount include ActionView::Helpers::TagHelper include ActionView::Helpers::TextHelper attr_accessor :output_buffer + mattr_accessor :camelize_props_switch # ControllerLifecycle calls these hooks # You can use them in custom helper implementations @@ -23,8 +24,8 @@ def teardown(env) # on the client. def react_component(name, props = {}, options = {}, &block) options = {:tag => options} if options.is_a?(Symbol) - props = camelize_props_key(props) - + props = camelize_props_key(props) if camelize_props_switch + prerender_options = options[:prerender] if prerender_options block = Proc.new{ concat React::ServerRendering.render(name, props, prerender_options) } diff --git a/lib/react/rails/railtie.rb b/lib/react/rails/railtie.rb index c90d16672..a54691633 100644 --- a/lib/react/rails/railtie.rb +++ b/lib/react/rails/railtie.rb @@ -9,6 +9,8 @@ class Railtie < ::Rails::Railtie config.react.addons = false config.react.jsx_transform_options = {} config.react.jsx_transformer_class = nil # defaults to BabelTransformer + config.react.camelize_props = false # pass in an underscored hash but get a camelized hash + # Server rendering: config.react.server_renderer_pool_size = 1 # increase if you're on JRuby config.react.server_renderer_timeout = 20 # seconds @@ -31,6 +33,7 @@ class Railtie < ::Rails::Railtie app.config.react.view_helper_implementation ||= React::Rails::ComponentMount React::Rails::ViewHelper.helper_implementation_class = app.config.react.view_helper_implementation + React::Rails::ComponentMount.camelize_props_switch = app.config.react.camelize_props ActiveSupport.on_load(:action_controller) do include ::React::Rails::ControllerLifecycle diff --git a/test/react/rails/component_mount_test.rb b/test/react/rails/component_mount_test.rb index d8d99ffa6..cd58c6cee 100644 --- a/test/react/rails/component_mount_test.rb +++ b/test/react/rails/component_mount_test.rb @@ -13,6 +13,16 @@ class ComponentMountTest < ActionDispatch::IntegrationTest end end + test '#react_component accepts React props with camelize_props ' do + React::Rails::ComponentMount.camelize_props_switch = true + helper = React::Rails::ComponentMount.new + html = helper.react_component('Foo', {foo_bar: 'value'}) + expected_props = %w(data-react-class="Foo" data-react-props="{"fooBar":"value"}") + expected_props.each do |segment| + assert html.include?(segment) + end + end + test '#react_component accepts jbuilder-based strings as properties' do jbuilder_json = Jbuilder.new do |json| json.bar 'value'