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 9b8f1db44..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,6 +24,7 @@ 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) if camelize_props_switch prerender_options = options[:prerender] if prerender_options @@ -41,6 +43,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/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'