Skip to content

Commit 75ae868

Browse files
committed
react_component_hash always has pre-render true
* Makes no sense to have react_component_hash not use prerrender. * Fixed issue where checking gem existence. * Added docs for react_component_hash
1 parent 3a43054 commit 75ae868

File tree

5 files changed

+70
-10
lines changed

5 files changed

+70
-10
lines changed

README.md

+43
Original file line numberDiff line numberDiff line change
@@ -357,10 +357,16 @@ You have 2 ways to specify your React components. You can either register the Re
357357
358358
ReactOnRails will automatically detect a registered generator function. Thus, there is no difference between registering a React Component versus a "generator function."
359359
360+
#### react_component_hash for Generator Functions
360361
Another reason to use a generator function is that sometimes in server rendering, specifically with React Router, you need to return the result of calling ReactDOMServer.renderToString(element). You can do this by returning an object with the following shape: { renderedHtml, redirectLocation, error }. Make sure you use this function with `react_component_hash`.
361362
362363
For server rendering, if you wish to return multiple HTML strings from a generator function, you may return an Object from your generator function with a single top level property of `renderedHtml`. Inside this Object, place a key called `componentHtml`, along with any other needed keys. An example scenario of this is when you are using side effects libraries like [React Helmet](https://github.com/nfl/react-helmet). Your Ruby code will get this Object as a Hash containing keys componentHtml and any other custom keys that you added:
364+
365+
```js
363366
{ renderedHtml: { componentHtml, customKey1, customKey2} }
367+
```
368+
369+
For details on using react_component_hash with react-helmet, see the docs below for the helper API and [docs/additional-reading/react-helmet.md](../docs/additional-reading/react-helmet.md).
364370

365371
### Rails Context and Generator Functions
366372
When you use a "generator function" to create react components (or renderedHtml on the server), or you used shared redux stores, you get two params passed to your function that creates a React component:
@@ -535,7 +541,44 @@ All options except `props, id, html_options` will inherit from your `react_on_ra
535541
+ **replay_console:** Default is true. False will disable echoing server-rendering logs to the browser. While this can make troubleshooting server rendering difficult, so long as you have the configuration of `logging_on_server` set to true, you'll still see the errors on the server.
536542
+ **logging_on_server:** Default is true. True will log JS console messages and errors to the server.
537543
+ **raise_on_prerender_error:** Default is false. True will throw an error on the server side rendering. Your controller will have to handle the error.
544+
545+
### react_component_hash
546+
`react_component_hash` is used to return multiple HTML strings for server rendering, such as for
547+
adding meta-tags to a page. It is exactly like react_component except for the following:
548+
549+
1. `prerender: true` is automatically added to options, as this method doesn't make sense for
550+
client only rendering.
551+
2. Your JavaScript for server rendering must return an Object for the key `server_rendered_html`.
552+
3. Your view code must expect an object and not a string.
553+
554+
Here is an example of ERB view code:
555+
556+
```erb
557+
<% react_helmet_app = react_component_hash("ReactHelmetApp", prerender: true,
558+
props: { helloWorldData: { name: "Mr. Server Side Rendering"}},
559+
id: "react-helmet-0", trace: true) %>
560+
<% content_for :title do %>
561+
<%= react_helmet_app['title'] %>
562+
<% end %>
563+
<%= react_helmet_app["componentHtml"] %>
564+
```
538565

566+
And here is the JavaScript code:
567+
568+
```js
569+
export default (props, _railsContext) => {
570+
const componentHtml = renderToString(<ReactHelmet {...props} />);
571+
const helmet = Helmet.renderStatic();
572+
573+
const renderedHtml = {
574+
componentHtml,
575+
title: helmet.title.toString(),
576+
};
577+
return { renderedHtml };
578+
};
579+
580+
```
581+
539582
### redux_store
540583
#### Controller Extension
541584
Include the module `ReactOnRails::Controller` in your controller, probably in ApplicationController. This will provide the following controller method, which you can call in your controller actions:

lib/react_on_rails/react_on_rails_helper.rb

+24-6
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,35 @@ def react_component(component_name, options = {})
120120

121121
else
122122
msg = <<-MSG.strip_heredoc
123-
ReactOnRails: server_rendered_html is expected to be a String. If you're trying to
124-
use a generator function to return a Hash to your ruby view code, then use
123+
ReactOnRails: server_rendered_html is expected to be a String for #{component_name}. If you're
124+
trying to use a generator function to return a Hash to your ruby view code, then use
125125
react_component_hash instead of react_component and see
126126
https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
127-
for an example of the necessary javascript configuration."
127+
for an example of the JavaScript code."
128128
MSG
129129
raise ReactOnRails::Error, msg
130130
end
131131
end
132132

133+
# react_component_hash is used to return multiple HTML strings for server rendering, such as for
134+
# adding meta-tags to a page.
135+
# It is exactly like react_component except for the following:
136+
# 1. prerender: true is automatically added, as this method doesn't make sense for client only
137+
# rendering.
138+
# 2. Your JavaScript for server rendering must return an Object for the key server_rendered_html.
139+
# 3. Your view code must expect an object and not a string.
140+
#
141+
# Here is an example of the view code:
142+
# <% react_helmet_app = react_component_hash("ReactHelmetApp", prerender: true,
143+
# props: { helloWorldData: { name: "Mr. Server Side Rendering"}},
144+
# id: "react-helmet-0", trace: true) %>
145+
# <% content_for :title do %>
146+
# <%= react_helmet_app['title'] %>
147+
# <% end %>
148+
# <%= react_helmet_app["componentHtml"] %>
149+
#
133150
def react_component_hash(component_name, options = {})
151+
options[:prerender] = true
134152
internal_result = internal_react_component(component_name, options)
135153
server_rendered_html = internal_result[:result]["html"]
136154
console_script = internal_result[:result]["consoleReplayScript"]
@@ -148,9 +166,9 @@ def react_component_hash(component_name, options = {})
148166
)
149167
else
150168
msg = <<-MSG.strip_heredoc
151-
Generator function used by react_component_hash is expected to return an Object. See
152-
https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
153-
for an example of the necessary javascript configuration.
169+
Generator function used by react_component_hash for #{component_name} is expected to return
170+
an Object. See https://github.com/shakacode/react_on_rails/blob/master/spec/dummy/client/app/startup/ReactHelmetServerApp.jsx
171+
for an example of the JavaScript code."
154172
MSG
155173
raise ReactOnRails::Error, msg
156174
end

lib/react_on_rails/utils.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,11 @@ def self.generated_assets_full_path
140140
end
141141

142142
def self.gem_available?(name)
143-
Gem::Specification.find_by_name(name)
143+
Gem::Specification.find_by_name(name).present?
144144
rescue Gem::LoadError
145145
false
146146
rescue StandardError
147-
Gem.available?(name)
147+
Gem.available?(name).present?
148148
end
149149

150150
def self.react_on_rails_pro?

spec/dummy/app/views/pages/broken_app.html.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<%= react_component_hash("BrokenApp", prerender: true)['componentHtml'] %>
1+
<%= react_component_hash("BrokenApp")['componentHtml'] %>
22

33
<hr/>
44

spec/dummy/app/views/pages/react_helmet.erb

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11

22
<% react_helmet_app = react_component_hash("ReactHelmetApp",
3-
prerender: true,
43
props: { helloWorldData: { name: "Mr. Server Side Rendering"}},
54
id: "react-helmet-0",
65
trace: true) %>

0 commit comments

Comments
 (0)