diff --git a/README.md b/README.md index 5e3bb7abe..fd01631ea 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,17 @@ react_component('HelloMessage', {name: 'John'}, {prerender: true}) ``` This will return the fully rendered component markup, and as long as you have included the `react_ujs` script in your page, then the component will also be instantiated and mounted on the client. +#### Preload globals + +If you want to preload some global variables, generated by Gon for example, +use the same view helper `react_component`, and pass in `context_suffix: 'some loading javascript'` in the `options` hash. + +```erb +react_component('HelloMessage', {name: 'John'}, {prerender: true, context_suffix: 'window.myVar = 123;'}) +``` + +This will return the fully rendered component markup, that can use preloaded variables + ## Configuring ### Variants diff --git a/lib/react/rails/view_helper.rb b/lib/react/rails/view_helper.rb index 23e0cac66..d1ac35e04 100644 --- a/lib/react/rails/view_helper.rb +++ b/lib/react/rails/view_helper.rb @@ -8,7 +8,8 @@ module ViewHelper # def react_component(name, args = {}, options = {}, &block) options = {:tag => options} if options.is_a?(Symbol) - block = Proc.new{concat React::Renderer.render(name, args)} if options[:prerender] == true + context_suffix = options.delete(:context_suffix) || '' + block = Proc.new{concat React::Renderer.render(name, args, context_suffix)} if options[:prerender] == true html_options = options.reverse_merge(:data => {}) html_options[:data].tap do |data| diff --git a/lib/react/renderer.rb b/lib/react/renderer.rb index a8909f943..74853cc4b 100644 --- a/lib/react/renderer.rb +++ b/lib/react/renderer.rb @@ -21,9 +21,9 @@ def self.setup!(react_js, components_js, args={}) @@pool = ConnectionPool.new(:size => args[:size]||10, :timeout => args[:timeout]||20) { self.new } end - def self.render(component, args={}) + def self.render(component, args={}, context_suffix='') @@pool.with do |renderer| - renderer.render(component, args) + renderer.render(component, args, context_suffix) end end @@ -62,18 +62,26 @@ def self.react_props(args={}) end end - def context - @context ||= ExecJS.compile(self.class.combined_js) + def context(suffix_code='') + if suffix_code.present? + reset_context(suffix_code) + else + @context ||= ExecJS.compile(self.class.combined_js) + end + end + + def reset_context(suffix_code='') + @context = ExecJS.compile(self.class.combined_js + suffix_code) end - def render(component, args={}) + def render(component, args={}, context_suffix='') react_props = React::Renderer.react_props(args) jscode = <<-JS function() { return React.renderToString(React.createElement(#{component}, #{react_props})); }() JS - context.eval(jscode).html_safe + context(context_suffix).eval(jscode).html_safe rescue ExecJS::ProgramError => e raise PrerenderError.new(component, react_props, e) end diff --git a/test/dummy/app/assets/javascripts/components/TodoGlobalList.js.jsx b/test/dummy/app/assets/javascripts/components/TodoGlobalList.js.jsx new file mode 100644 index 000000000..351e94c79 --- /dev/null +++ b/test/dummy/app/assets/javascripts/components/TodoGlobalList.js.jsx @@ -0,0 +1,18 @@ +TodoGlobalList = React.createClass({ + getInitialState: function() { + return({mounted: "nope"}); + }, + componentWillMount: function() { + this.setState({mounted: 'yep'}); + }, + render: function() { + return ( +