react-rails 1.11.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/README.md +294 -214
  4. data/lib/assets/javascripts/react_ujs.js +429 -7
  5. data/lib/generators/react/component_generator.rb +24 -12
  6. data/lib/generators/react/install_generator.rb +76 -18
  7. data/lib/generators/templates/react_server_rendering.rb +2 -0
  8. data/lib/generators/templates/server_rendering.js +6 -0
  9. data/lib/generators/templates/server_rendering_pack.js +5 -0
  10. data/lib/react/jsx.rb +2 -0
  11. data/lib/react/rails/component_mount.rb +23 -5
  12. data/lib/react/rails/controller_lifecycle.rb +35 -7
  13. data/lib/react/rails/railtie.rb +17 -11
  14. data/lib/react/rails/version.rb +1 -1
  15. data/lib/react/server_rendering.rb +16 -4
  16. data/lib/react/server_rendering/{sprockets_renderer.rb → bundle_renderer.rb} +40 -20
  17. data/lib/react/server_rendering/{sprockets_renderer → bundle_renderer}/console_polyfill.js +0 -0
  18. data/lib/react/server_rendering/{sprockets_renderer → bundle_renderer}/console_replay.js +1 -1
  19. data/lib/react/server_rendering/bundle_renderer/console_reset.js +3 -0
  20. data/lib/react/server_rendering/{sprockets_renderer → bundle_renderer}/timeout_polyfill.js +0 -0
  21. data/lib/react/server_rendering/exec_js_renderer.rb +4 -1
  22. data/lib/react/server_rendering/webpacker_manifest_container.rb +34 -0
  23. data/lib/react/server_rendering/yaml_manifest_container.rb +1 -1
  24. metadata +16 -16
  25. data/lib/assets/javascripts/react_ujs_event_setup.js +0 -29
  26. data/lib/assets/javascripts/react_ujs_mount.js +0 -104
  27. data/lib/assets/javascripts/react_ujs_native.js +0 -18
  28. data/lib/assets/javascripts/react_ujs_pjax.js +0 -10
  29. data/lib/assets/javascripts/react_ujs_turbolinks.js +0 -9
  30. data/lib/assets/javascripts/react_ujs_turbolinks_classic.js +0 -10
  31. data/lib/assets/javascripts/react_ujs_turbolinks_classic_deprecated.js +0 -13
  32. data/lib/generators/react/ujs_generator.rb +0 -44
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5be5071bf0476f2792eff912d657e0bf93ead10e
4
- data.tar.gz: 2c77127d9a17d3ba653086034c61a087714f0476
3
+ metadata.gz: e9fe44131627108a965e3ab9eb09d5dfd1880926
4
+ data.tar.gz: aabdd492d7f9dd5cf9e17d7f10ef8547749cb8ca
5
5
  SHA512:
6
- metadata.gz: 8fab516013ce7f24199968b2ed3f6183998921fa97632afb2ea4beff96fcb4bf85a8c8371d383cb60d0a866501dc770f39d6a8ae00906603a11d5520a4d1f521
7
- data.tar.gz: 79d8ca952f890e00e8116939ba4136229c470c34ba5424bf9ca7eae052c3dbf67c7646fa3e3fdc4126e29241de25abc257ffd01c93375c293098bdd374012107
6
+ metadata.gz: 0e13b6d9112c96ca74ecc0f2fc78540fc6577a63f7e46ae2e5cb9fa481726d5f879d8f63a2e5f479c572398bea14c3b37bed4c45952175e287d6dfd02602a0f8
7
+ data.tar.gz: d8c03917cabcf1d59b399fb10162642f5e76ea31b8d4f08ef5d223a3e2c713250c536a421db8f44d480ffae16d20f15b79b015bc5950a3977ff8796aea194805
@@ -8,6 +8,35 @@
8
8
 
9
9
  #### Bug Fixes
10
10
 
11
+ ## 2.0.0 (April 13, 2017)
12
+
13
+ #### Breaking Changes
14
+
15
+ - Server rendering loads `server_rendering.js` by default #471 . Upgrade by adding a new file which requires the previous defaults:
16
+
17
+ ```js
18
+ // app/assets/javascripts/server_rendering.js
19
+ // = require react-server
20
+ // = require components
21
+ ```
22
+
23
+
24
+ #### New Features
25
+
26
+ - Webpacker support:
27
+ - `react_component` can find components via `require.context` + `ReactRailsUJS.useContext` #678
28
+ - Server rendering detects Webpacker and uses packs #683, #687
29
+ - `ReactRailsUJS` is available from `npm` with `yarn add react_ujs` or `npm install react_ujs` #678
30
+ - `per_request_react_rails_prerenderer` Allows you to check out a renderer for the _whole request_ instead of once-per-`react_component` #559
31
+
32
+ #### Bug Fixes
33
+
34
+ - Improved watching of server-rendering JS files #687
35
+ - Fix console replay:
36
+ - Put the `<script>` tag outside the React.js container to avoid React warnings #691
37
+ - Clear console history between renders #692
38
+ - Use better Turbolinks events #690
39
+
11
40
  ## 1.11.0 (April 4, 2017)
12
41
 
13
42
  #### New Features
data/README.md CHANGED
@@ -1,116 +1,176 @@
1
+ # react-rails
2
+
1
3
  [![Gem](https://img.shields.io/gem/v/react-rails.svg?style=flat-square)](http://rubygems.org/gems/react-rails)
2
4
  [![Build Status](https://img.shields.io/travis/reactjs/react-rails/master.svg?style=flat-square)](https://travis-ci.org/reactjs/react-rails)
3
5
  [![Gemnasium](https://img.shields.io/gemnasium/reactjs/react-rails.svg?style=flat-square)](https://gemnasium.com/reactjs/react-rails)
4
6
  [![Code Climate](https://img.shields.io/codeclimate/github/reactjs/react-rails.svg?style=flat-square)](https://codeclimate.com/github/reactjs/react-rails)
5
7
  [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/reactjs/react-rails.svg?style=flat-square)](https://codeclimate.com/github/reactjs/react-rails/coverage)
6
8
 
7
- * * *
9
+ `react-rails` makes it easy to use [React](http://facebook.github.io/react/) and [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html) in your Ruby on Rails (3.2+) application. Learn more:
8
10
 
9
- # react-rails
11
+ - React's [Getting Started guide](https://facebook.github.io/react/docs/getting-started.html)
12
+ - Use React & JSX [with webpacker](#use-with-webpacker) or [with the asset pipeline](#use-with-asset-pipeline)
13
+ - Rendering [components in views](#view-helper) or [in controller actions](#controller-actions)
14
+ - [Server-side rendering](#server-side-rendering)
15
+ - [Generating components](#component-generator) in various formats
16
+ - [`ReactRailsUJS`](#ujs) for mounting and unmounting components
17
+ - Automatically [camelizing props](#camelize-props)
18
+ - [Related Projects](#related-projects)
19
+ - [Developing](#development) the gem
10
20
 
21
+ ## Installation
11
22
 
12
- `react-rails` makes it easy to use [React](http://facebook.github.io/react/) and [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html)
13
- in your Ruby on Rails (3.2+) application. `react-rails` can:
23
+ Install from Rubygems as `react-rails`.
14
24
 
15
- - Provide [various `react` builds](#reactjs-builds) to your asset bundle
16
- - Transform [`.jsx` in the asset pipeline](#jsx)
17
- - [Render components into views and mount them](#rendering--mounting) via view helper & `react_ujs`
18
- - [Render components server-side](#server-rendering) with `prerender: true`
19
- - [Generate components](#component-generator) with a Rails generator
20
- - [Be extended](#extending-react-rails) with custom renderers, transformers and view helpers
25
+ ```ruby
26
+ gem "react-rails"
27
+ ```
21
28
 
22
- Just getting started with React? Make sure to check out the [Getting Started][React Getting Started] guide. Also, see [Related Projects](#related-projects) below.
29
+ Get started with `rails g react:install`:
23
30
 
24
- ## Installation
31
+ ```
32
+ $ rails g react:install
33
+ ```
25
34
 
26
- Add `react-rails` to your gemfile:
35
+ ## Use with Webpacker
27
36
 
28
- ```ruby
29
- gem 'react-rails'
37
+ [webpacker](https://github.com/rails/webpacker) integrates modern JS tooling with Rails. `ReactRailsUJS` allows you to gradually migrate to webpacker.
38
+
39
+ Get started by adding `webpacker` to your gemfile and installing `webpacker` and `react-rails`:
40
+
41
+ ```
42
+ $ rails webpacker:install
43
+ $ rails webpacker:install:react
44
+ $ rails generate react:install
30
45
  ```
31
46
 
32
- And install:
47
+ This gives you:
48
+
49
+ - `components/` directory for your React components
50
+ - [`ReactRailsUJS`](#ujs) setup in `packs/application.js`
51
+ - `packs/server_rendering.js` for [server-side rendering](#server-side-rendering)
33
52
 
53
+ When you add a component to `components/`, you can [render it in a Rails view](#view-helper):
54
+
55
+ ```erb
56
+ <%= react_component("HelloWorld", { greeting: "Hello" }) %>
34
57
  ```
35
- bundle install
58
+
59
+ The component name tells `react-rails` where to load the component. For example:
60
+
61
+ `react_component` call | component `require`
62
+ =======================|======================
63
+ `react_component("Item")` | `require("Item")`
64
+ `react_component("items/index")` | `require("items/index")`
65
+ `react_component("items.Index")` | `require("items").Index`
66
+ `react_component("items.Index.Header")` | `require("items").Index.Header`
67
+
68
+ This way, you can access top-level, default, or named exports.
69
+
70
+ If `require` fails, `react-rails` falls back to the global namespace approach described in [Use with Asset Pipeline](#use-with-asset-pipeline).
71
+
72
+ The `require.context` inserted into `packs/application.js` is used to load components. If you want to load components from a different directory, override it by calling `ReactRailsUJS.useContext`:
73
+
74
+ ```js
75
+ var myCustomContext = require.context("custom_components", true)
76
+ var ReactRailsUJS = require("react_ujs")
77
+ // use `custom_components/` for <%= react_component(...) %> calls
78
+ ReactRailsUJS.useContext(myCustomContext)
36
79
  ```
37
80
 
38
- Next, run the installation script:
81
+ ## Use with Asset Pipeline
39
82
 
40
- ```bash
41
- rails g react:install
83
+ `react-rails` provides React.js & a UJS driver to the Rails asset pipeline. Get started by installing:
84
+
85
+ ```
86
+ $ rails g react:install
42
87
  ```
43
88
 
89
+ Then restart your development server.
90
+
44
91
  This will:
45
- - create a `components.js` manifest file and a `app/assets/javascripts/components/` directory,
46
- where you will put your components
47
- - place the following in your `application.js`:
48
92
 
49
- ```js
50
- //= require react
51
- //= require react_ujs
52
- //= require components
53
- ```
93
+ - add some `//= require`s to `application.js`
94
+ - add a `components/` directory for React components
95
+ - add `server_rendering.js` for [server-side rendering](#server-side-rendering)
54
96
 
55
- ## Usage
97
+ Now, you can create React components in `.jsx` files:
56
98
 
57
- ### React.js builds
99
+ ```js
100
+ // app/assets/javascripts/components/post.jsx
58
101
 
59
- You can pick which React.js build (development, production, with or without [add-ons]((http://facebook.github.io/react/docs/addons.html)))
60
- to serve in each environment by adding a config. Here are the defaults:
102
+ window.Post = React.createClass({
103
+ render: function() {
104
+ return <h1>{this.props.title}</h1>
105
+ }
106
+ })
61
107
 
62
- ```ruby
63
- # config/environments/development.rb
64
- MyApp::Application.configure do
65
- config.react.variant = :development
66
- end
108
+ // or, equivalent:
109
+ class Post extends React.Component {
110
+ render() {
111
+ return <h1>{this.props.title}</h1>
112
+ }
113
+ }
114
+ ```
67
115
 
68
- # config/environments/production.rb
69
- MyApp::Application.configure do
70
- config.react.variant = :production
71
- end
116
+ Then, you can render those [components in views](#view-helper):
117
+
118
+ ```erb
119
+ <%= react_component("Post", {title: "Hello World"}) %>
72
120
  ```
73
121
 
74
- To include add-ons, use this config:
122
+ Components must be accessible from the top level, but they may be namespaced, for example:
75
123
 
76
- ```ruby
77
- MyApp::Application.configure do
78
- config.react.addons = true # defaults to false
79
- end
124
+ ```erb
125
+ <%= react_component("Comments.NewForm", {post_id: @post.id}) %>
126
+ <!-- looks for `window.Comments.NewForm` -->
80
127
  ```
81
128
 
82
- After restarting your Rails server, `//= require react` will provide the build of React.js which
83
- was specified by the configurations.
129
+ ### Custom JSX Transformer
130
+
131
+ `react-rails` uses a transformer class to transform JSX in the asset pipeline. The transformer is initialized once, at boot. You can provide a custom transformer to `config.react.jsx_transformer_class`. The transformer must implement:
84
132
 
85
- `react-rails` offers a few other options for versions & builds of React.js.
86
- See [VERSIONS.md](https://github.com/reactjs/react-rails/blob/master/VERSIONS.md) for more info about
87
- using the `react-source` gem or dropping in your own copies of React.js.
133
+ - `#initialize(options)`, where options is the value passed to `config.react.jsx_transform_options`
134
+ - `#transform(code_string)` to return a string of transformed code
88
135
 
89
- ### JSX
136
+ `react-rails` provides two transformers, `React::JSX::BabelTransformer` (which uses [ruby-babel-transpiler](https://github.com/babel/ruby-babel-transpiler)) and `React::JSX::JSXTransformer` (which uses the deprecated `JSXTransformer.js`).
90
137
 
91
- After installing `react-rails`, restart your server. Now, `.js.jsx` files will be transformed in the asset pipeline.
138
+ ### React.js versions
92
139
 
93
- #### BabelTransformer options
140
+ `//= require react` brings `React` into your project.
94
141
 
95
- You can use babel's [transformers](http://henryzoo.com/babel.github.io/docs/advanced/transformers/) and [custom plugins](http://henryzoo.com/babel.github.io/docs/advanced/plugins/),
96
- and pass [options](http://babeljs.io/docs/usage/options/) to the babel transpiler adding following configurations:
142
+ To include `React.addons`, add this config:
97
143
 
98
144
  ```ruby
99
- config.react.jsx_transform_options = {
100
- blacklist: ['spec.functionName', 'validation.react', 'strict'], # default options
101
- optional: ["transformerName"], # pass extra babel options
102
- whitelist: ["useStrict"] # even more options
103
- }
145
+ # config/application.rb
146
+ MyApp::Application.configure do
147
+ config.react.addons = true # defaults to false
148
+ end
149
+ ```
150
+
151
+ By default, React's [development version] is provided to `Rails.env.development`. You can override the React build with a config:
152
+
153
+ ```ruby
154
+ # Here are the defaults:
155
+ # config/environments/development.rb
156
+ MyApp::Application.configure do
157
+ config.react.variant = :development
158
+ end
159
+
160
+ # config/environments/production.rb
161
+ MyApp::Application.configure do
162
+ config.react.variant = :production
163
+ end
104
164
  ```
105
- Under the hood, `react-rails` uses [ruby-babel-transpiler](https://github.com/babel/ruby-babel-transpiler), for transformation.
106
165
 
107
- ### Rendering & mounting
166
+ Be sure to restart your Rails server after changing these files. See [VERSIONS.md](https://github.com/reactjs/react-rails/blob/master/VERSIONS.md) to learn which version of React.js is included with your `react-rails` version.
167
+
168
+
169
+ ## View Helper
108
170
 
109
- `react-rails` includes a view helper (`react_component`) and an unobtrusive JavaScript driver (`react_ujs`)
110
- which work together to put React components on the page. You should require the UJS driver
111
- in your manifest after `react` (and after `turbolinks` if you use [Turbolinks](https://github.com/rails/turbolinks)).
171
+ `react-rails` includes a view helper and an [unobtrusive JavaScript driver](#ujs) which work together to put React components on the page.
112
172
 
113
- The __view helper__ puts a `div` on the page with the requested component class & props. For example:
173
+ The view helper (`react_component`) puts a `div` on the page with the requested component class & props. For example:
114
174
 
115
175
  ```erb
116
176
  <%= react_component('HelloMessage', name: 'John') %>
@@ -118,35 +178,87 @@ The __view helper__ puts a `div` on the page with the requested component class
118
178
  <div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}"></div>
119
179
  ```
120
180
 
121
- On page load, the __`react_ujs` driver__ will scan the page and mount components using `data-react-class`
181
+ On page load, the [`react_ujs` driver](#ujs) will scan the page and mount components using `data-react-class`
122
182
  and `data-react-props`.
123
183
 
124
- If Turbolinks is present components are mounted on the `page:change` event, and unmounted on `page:before-unload`.
125
- __Turbolinks >= 2.4.0__ is recommended because it exposes better events.
126
-
127
- In case of __Ajax calls__, the UJS mounting can be triggered manually by calling from javascript:
128
-
129
- ```javascript
130
- ReactRailsUJS.mountComponents()
131
- ```
132
-
133
184
  The view helper's signature is:
134
185
 
135
186
  ```ruby
136
187
  react_component(component_class_name, props={}, html_options={})
137
188
  ```
138
189
 
139
- - `component_class_name` is a string which names a globally-accessible component class. It may have dots (eg, `"MyApp.Header.MenuItem"`).
140
- - `props` is either an object that responds to `#to_json` or an already-stringified JSON object (eg, made with Jbuilder, see note below).
190
+ - `component_class_name` is a string which identifies a component. See [getConstructor](#getconstructor) for details.
191
+ - `props` is either:
192
+ - an object that responds to `#to_json`; or
193
+ - an already-stringified JSON object (see [JBuilder note](#use-with-jbuilder) below).
141
194
  - `html_options` may include:
142
195
  - `tag:` to use an element other than a `div` to embed `data-react-class` and `data-react-props`.
143
196
  - `prerender: true` to render the component on the server.
197
+ - `camelize_props` to [transform a props hash](#camelize_props)
144
198
  - `**other` Any other arguments (eg `class:`, `id:`) are passed through to [`content_tag`](http://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag).
145
199
 
146
200
 
147
- ### Server rendering
201
+ #### Custom View Helper
202
+
203
+ `react-rails` uses a "helper implementation" class to generate the output of the `react_component` helper. The helper is initialized once per request and used for each `react_component` call during that request. You can provide a custom helper class to `config.react.view_helper_implementation`. The class must implement:
204
+
205
+ - `#react_component(name, props = {}, options = {}, &block)` to return a string to inject into the Rails view
206
+ - `#setup(controller_instance)`, called when the helper is initialized at the start of the request
207
+ - `#teardown(controller_instance)`, called at the end of the request
208
+
209
+ `react-rails` provides one implementation, `React::Rails::ComponentMount`.
210
+
211
+ ## UJS
212
+
213
+ `react-rails`'s JavaScript is available as `"react_ujs"` in the asset pipeline or from NPM. It attaches itself to the window as `ReactRailsUJS`.
214
+
215
+ ### Mounting & Unmounting
216
+
217
+ Usually, `react-rails` mounts & unmounts components automatically as described in [Event Handling](#event-handling) below.
218
+
219
+ You can also mount & unmount components from `<%= react_component(...) %>` tags using UJS:
220
+
221
+ ```js
222
+ // Mount all components on the page:
223
+ ReactRailsUJS.mountComponents()
224
+ // Mount components within a selector:
225
+ ReactRailsUJS.mountComponents(".my-class")
226
+ // Mount components within a specific node:
227
+ ReactRailsUJS.mountComponents(specificDOMnode)
228
+
229
+ // Unmounting works the same way:
230
+ ReactRailsUJS.unmountComponents()
231
+ ReactRailsUJS.unmountComponents(".my-class")
232
+ ReactRailsUJS.unmountComponents(specificDOMnode)
233
+ ```
234
+
235
+ You can use this when the DOM is modified by AJAX calls or modal windows.
236
+
237
+ ### Event Handling
238
+
239
+ `ReactRailsUJS` checks for various libraries to support their page change events:
240
+
241
+ - `Turbolinks`
242
+ - `pjax`
243
+ - `jQuery`
244
+ - Native DOM events
245
+
246
+ `ReactRailsUJS` will automatically mount components on `<%= react_component(...) %>` tags and unmount them when appropriate.
247
+
248
+ Be sure to load `react_ujs` _after_ these libraries so that it can detect them.
249
+
250
+ ### `getConstructor`
251
+
252
+ Components are loaded with `ReactRailsUJS.getConstructor(className)`. This function has two built-in implementations:
253
+
254
+ - On the asset pipeline, it looks up `className` in the global namespace.
255
+ - On webpacker, it `require`s files and accesses named exports, as described in [Use with Webpacker](#use-with-webpacker).
148
256
 
149
- To render components on the server, pass `prerender: true` to `react_component`:
257
+ You can override this function to customize the mapping of name-to-constructor. [Server-side rendering](#server-side-rendering) also uses this function.
258
+
259
+ ## Server-Side Rendering
260
+
261
+ You can render React components inside your Rails server with `prerender: true`:
150
262
 
151
263
  ```erb
152
264
  <%= react_component('HelloMessage', {name: 'John'}, {prerender: true}) %>
@@ -156,25 +268,22 @@ To render components on the server, pass `prerender: true` to `react_component`:
156
268
  </div>
157
269
  ```
158
270
 
159
- _(It will also be mounted by the UJS on page load.)_
271
+ _(It will also be mounted by the [UJS](#ujs) on page load.)_
160
272
 
161
- There are some requirements for this to work:
273
+ Server rendering is powered by [`ExecJS`](https://github.com/rails/execjs) and subject to some requirements:
162
274
 
163
- - `react-rails` must load your code. By convention, it uses `components.js`, which was created
275
+ - `react-rails` must load your code. By convention, it uses `server_rendering.js`, which was created
164
276
  by the install task. This file must include your components _and_ their dependencies (eg, Underscore.js).
165
- - Your components must be accessible in the global scope.
166
- If you are using `.js.jsx.coffee` files then the wrapper function needs to be taken into account:
167
-
168
- ```coffee
169
- # @ is `window`:
170
- @Component = React.createClass
171
- render: ->
172
- `<ExampleComponent videos={this.props.videos} />`
173
- ```
174
- - Your code can't reference `document`. Prerender processes don't have access to `document`,
277
+ - Your code can't reference `document` or `window`. Prerender processes don't have access to `document` or `window`,
175
278
  so jQuery and some other libs won't work in this environment :(
176
279
 
177
- You can configure your pool of JS virtual machines and specify where it should load code:
280
+ `ExecJS` supports many backends. CRuby users will get the best performance from [`mini_racer`](https://github.com/discourse/mini_racer#performance).
281
+
282
+ #### Configuration
283
+
284
+ Server renderers are stored in a pool and reused between requests. Threaded Rubies (eg jRuby) may see a benefit to increasing the pool size beyond the default `0`.
285
+
286
+ These are the default configurations:
178
287
 
179
288
  ```ruby
180
289
  # config/environments/application.rb
@@ -183,35 +292,71 @@ MyApp::Application.configure do
183
292
  # Settings for the pool of renderers:
184
293
  config.react.server_renderer_pool_size ||= 1 # ExecJS doesn't allow more than one on MRI
185
294
  config.react.server_renderer_timeout ||= 20 # seconds
186
- config.react.server_renderer = React::ServerRendering::SprocketsRenderer
295
+ config.react.server_renderer = React::ServerRendering::BundleRenderer
187
296
  config.react.server_renderer_options = {
188
- files: ["react-server.js", "components.js"], # files to load for prerendering
297
+ files: ["server_rendering.js"], # files to load for prerendering
189
298
  replay_console: true, # if true, console.* will be replayed client-side
190
299
  }
300
+ # Changing files matching these dirs/exts will cause the server renderer to reload:
301
+ config.react.server_renderer_extensions = ["jsx", "js"]
302
+ config.react.server_renderer_directories = ["/app/assets/javascripts", "/app/javascripts/"]
191
303
  end
192
304
  ```
193
305
 
194
- - On MRI, use `therubyracer` for the best performance (see [discussion](https://github.com/reactjs/react-rails/pull/290))
195
- - On MRI, you'll get a deadlock with `pool_size` > 1
196
- - If you're using JRuby, you can increase `pool_size` to have real multi-threaded rendering.
306
+ #### JavaScript State
307
+
308
+ Some of ExecJS's backends are stateful (eg, mini_racer, therubyracer). This means that any side-effects of a prerender will affect later renders with that renderer.
197
309
 
198
- You can configure camelize_props option and pass props with an underscored hash from rails but get a camelized hash in jsx :
310
+ To manage state, you have a couple options:
311
+
312
+ - Make a custom renderer with `#before_render` / `#after_render` hooks as [described below](#custom-server-renderer)
313
+ - Use `per_request_react_rails_prerenderer` to manage state for a whole controller action.
314
+
315
+ To check out a renderer for the duration of a controller action, call the `per_request_react_rails_prerenderer` helper in the controller class:
199
316
 
200
317
  ```ruby
201
- MyApp::Application.configure do
202
- config.react.camelize_props = true #default false
318
+ class PagesController < ApplicationController
319
+ # Use the same React server renderer for the entire request:
320
+ per_request_react_rails_prerenderer
203
321
  end
204
322
  ```
205
323
 
206
- or when mounting:
324
+ Then, you can access the ExecJS context directly with `react_rails_prerenderer.context`:
207
325
 
208
- ```erb
209
- <%= react_component('HelloMessage', {name: 'John'}, {camelize_props: true}) %>
326
+ ```ruby
327
+ def show
328
+ react_rails_prerenderer # => #<React::ServerRendering::BundleRenderer>
329
+ react_rails_prerenderer.context # => #<ExecJS::Context>
330
+
331
+ # Execute arbitrary JavaScript code
332
+ # `self` is the global context
333
+ react_rails_prerenderer.context.exec("self.Store.setup()")
334
+ render :show
335
+ react_rails_prerenderer.context.exec("self.Store.teardown()")
336
+ end
210
337
  ```
211
338
 
212
- ### Rendering components instead of views
339
+ `react_rails_prerenderer` may also be accessed in before- or after-actions.
340
+
341
+ #### Custom Server Renderer
342
+
343
+ `react-rails` depends on a renderer class for rendering components on the server. You can provide a custom renderer class to `config.react.server_renderer`. The class must implement:
344
+
345
+ - `#initialize(options={})`, which accepts the hash from `config.react.server_renderer_options`
346
+ - `#render(component_name, props, prerender_options)` to return a string of HTML
347
+
348
+ `react-rails` provides two renderer classes: `React::ServerRendering::ExecJSRenderer` and `React::ServerRendering::BundleRenderer`.
349
+
350
+ `ExecJSRenderer` offers two other points for extension:
351
+
352
+ - `#before_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _before_ calling `React.render`
353
+ - `#after_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _after_ calling `React.render`
354
+
355
+ Any subclass of `ExecJSRenderer` may use those hooks (for example, `BundleRenderer` uses them to handle `console.*` on the server).
356
+
357
+ ## Controller Actions
213
358
 
214
- Components can also be prerendered directly from a controller action with the custom `component` renderer. For example:
359
+ Components can also be server-rendered directly from a controller action with the custom `component` renderer. For example:
215
360
 
216
361
  ```ruby
217
362
  class TodoController < ApplicationController
@@ -222,31 +367,30 @@ class TodoController < ApplicationController
222
367
  end
223
368
  ```
224
369
 
225
- This custom renderer behaves the same as a normal view renderer and accepts the usual arguments - `content_type`, `layout`, `location` and `status`.
226
- By default, your current layout will be used and the component, rather than a view, will be rendered in place of `yield`. Custom data-* attributes
227
- can be passed like `data: {remote: true}`. Prerendering is set to `true` by default, but can be turned off like any other option: `prerender: false`.
370
+ You can also provide the "usual" `render` arguments: `content_type`, `layout`, `location` and `status`. By default, your current layout will be used and the component, rather than a view, will be rendered in place of `yield`. Custom data-* attributes can be passed like `data: {remote: true}`.
228
371
 
229
- ### Component generator
372
+ Prerendering is set to `true` by default, but can be turned off with `prerender: false`.
230
373
 
231
- `react-rails` ships with a Rails generator to help you get started with a simple component scaffold.
232
- You can run it using `rails generate react:component ComponentName (--es6)`.
233
- The generator takes an optional list of arguments for default propTypes,
234
- which follow the conventions set in the [Reusable Components](http://facebook.github.io/react/docs/reusable-components.html)
235
- section of the React documentation.
374
+ ## Component Generator
236
375
 
237
- For example:
376
+ You can generate a new component file with:
238
377
 
239
- ```shell
240
- rails generate react:component Post title:string body:string published:bool published_by:instanceOf{Person}
378
+ ```sh
379
+ rails g react:component ComponentName prop1:type prop2:type ...
241
380
  ```
242
381
 
243
- would generate the following in `app/assets/javascripts/components/post.js.jsx`:
382
+ For example,
244
383
 
245
- ```jsx
384
+ ```sh
385
+ rails g react:component Post title:string published:bool published_by:instanceOf{Person}
386
+ ```
387
+
388
+ would generate:
389
+
390
+ ```js
246
391
  var Post = React.createClass({
247
392
  propTypes: {
248
393
  title: React.PropTypes.string,
249
- body: React.PropTypes.string,
250
394
  published: React.PropTypes.bool,
251
395
  publishedBy: React.PropTypes.instanceOf(Person)
252
396
  },
@@ -255,7 +399,6 @@ var Post = React.createClass({
255
399
  return (
256
400
  <div>
257
401
  <div>Title: {this.props.title}</div>
258
- <div>Body: {this.props.body}</div>
259
402
  <div>Published: {this.props.published}</div>
260
403
  <div>Published By: {this.props.publishedBy}</div>
261
404
  </div>
@@ -264,49 +407,22 @@ var Post = React.createClass({
264
407
  });
265
408
  ```
266
409
 
267
- #### Options
268
-
269
- **--es6** : Generate the same component but using cutting edge es6 class
270
-
271
- For example:
272
-
273
- ```shell
274
- rails generate react:component Label label:string --es6
275
- ```
276
-
277
- **--coffee** : Generate the component using CoffeeScript syntax
278
-
279
- For example:
280
-
281
- ```shell
282
- rails generate react:component Label label:string --coffee
283
- ```
284
-
285
- #### Arguments
410
+ The generator also accepts options:
286
411
 
287
- The generator can use the following arguments to create basic propTypes:
412
+ - `--es6`: use `class ComponentName extends React.Component`
413
+ - `--coffee`: use CoffeeScript
288
414
 
289
- * any
290
- * array
291
- * bool
292
- * element
293
- * func
294
- * number
295
- * object
296
- * node
297
- * shape
298
- * string
415
+ Accepted PropTypes are:
299
416
 
300
- The following additional arguments have special behavior:
301
-
302
- * `instanceOf` takes an optional class name in the form of {className}.
303
- * `oneOf` behaves like an enum, and takes an optional list of strings in the form of `'name:oneOf{one,two,three}'`.
304
- * `oneOfType` takes an optional list of react and custom types in the form of `'model:oneOfType{string,number,OtherType}'`.
417
+ - Plain types: `any`, `array`, `bool`, `element`, `func`, `number`, `object`, `node`, `shape`, `string`
418
+ - `instanceOf` takes an optional class name in the form of `instanceOf{className}`.
419
+ - `oneOf` behaves like an enum, and takes an optional list of strings in the form of `'name:oneOf{one,two,three}'`.
420
+ - `oneOfType` takes an optional list of react and custom types in the form of `'model:oneOfType{string,number,OtherType}'`.
305
421
 
306
422
  Note that the arguments for `oneOf` and `oneOfType` must be enclosed in single quotes
307
423
  to prevent your terminal from expanding them into an argument list.
308
424
 
309
- ### Jbuilder & react-rails
425
+ #### Use with JBuilder
310
426
 
311
427
  If you use Jbuilder to pass a JSON string to `react_component`, make sure your JSON is a stringified hash,
312
428
  not an array. This is not the Rails default -- you should add the root node yourself. For example:
@@ -325,68 +441,33 @@ json.messages(@messages) do |message|
325
441
  end
326
442
  ```
327
443
 
328
- ## CoffeeScript
444
+ ### Camelize Props
329
445
 
330
- It is possible to use JSX with CoffeeScript. To use CoffeeScript, create files with an extension `.js.jsx.coffee`.
331
- We also need to embed JSX code inside backticks so that CoffeeScript ignores the syntax it doesn't understand.
332
- Here's an example:
446
+ You can configure `camelize_props` option:
333
447
 
334
- ```coffee
335
- Component = React.createClass
336
- render: ->
337
- `<ExampleComponent videos={this.props.videos} />`
448
+ ```ruby
449
+ MyApp::Application.configure do
450
+ config.react.camelize_props = true # default false
451
+ end
338
452
  ```
339
453
 
340
- Alternatively, the newer ES6 style class based syntax can be used like this:
454
+ Now, Ruby hashes given to `react_component(...)` as props will have their keys transformed from _underscore_- to _camel_-case, for example:
341
455
 
342
- ```coffee
343
- class Component extends React.Component
344
- render: ->
345
- `<ExampleComponent videos={this.props.videos} />`
456
+ ```ruby
457
+ { all_todos: @todos, current_status: @status }
458
+ # becomes:
459
+ { "allTodos" => @todos, "currentStatus" => @status }
346
460
  ```
347
461
 
348
- ## Extending `react-rails`
349
-
350
- You can extend some of the core functionality of `react-rails` by injecting new implementations during configuration.
351
-
352
- ### Custom Server Renderer
353
-
354
- `react-rails` depends on a renderer class for rendering components on the server. You can provide a custom renderer class to `config.react.server_renderer`. The class must implement:
355
-
356
- - `#initialize(options={})`, which accepts the hash from `config.react.server_renderer_options`
357
- - `#render(component_name, props, prerender_options)` to return a string of HTML
358
-
359
- `react-rails` provides two renderer classes: `React::ServerRendering::ExecJSRenderer` and `React::ServerRendering::SprocketsRenderer`.
360
-
361
- `ExecJSRenderer` offers two other points for extension:
362
-
363
- - `#before_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _before_ calling `React.render`
364
- - `#after_render(component_name, props, prerender_options)` to return a string of JavaScript to execute _after_ calling `React.render`
365
-
366
- Any subclass of `ExecJSRenderer` may use those hooks (for example, `SprocketsRenderer` uses them to handle `console.*` on the server).
367
-
368
- ### Custom View Helper
369
-
370
- `react-rails` uses a "helper implementation" class to generate the output of the `react_component` helper. The helper is initialized once per request and used for each `react_component` call during that request. You can provide a custom helper class to `config.react.view_helper_implementation`. The class must implement:
371
-
372
- - `#react_component(name, props = {}, options = {}, &block)` to return a string to inject into the Rails view
373
- - `#setup(controller_instance)`, called when the helper is initialized at the start of the request
374
- - `#teardown(controller_instance)`, called at the end of the request
375
-
376
- `react-rails` provides one implementation, `React::Rails::ComponentMount`.
377
-
378
- ### Custom JSX Transformer
462
+ You can also specify this option in `react_component`:
379
463
 
380
- `react-rails` uses a transformer class to transform JSX for the browser. The transformer is initialized once, at boot. You can provide a custom transformer to `config.react.jsx_transformer_class`. The transformer must implement:
381
-
382
- - `#initialize(options)`, where options is the value passed to `config.react.jsx_transform_options`
383
- - `#transform(code_string)` to return a string of transformed code
384
-
385
- `react-rails` provides two transformers, `React::JSX::JSXTransformer` and `React::JSX::BabelTransformer`.
464
+ ```erb
465
+ <%= react_component('HelloMessage', {name: 'John'}, {camelize_props: true}) %>
466
+ ```
386
467
 
387
- ### Related Projects
468
+ ## Related Projects
388
469
 
389
- - [react\_on\_rails Gem](https://github.com/shakacode/react_on_rails): Webpack Integration of React with Rails utilizing the modern JavaScript tooling and libraries, including Webpack, Babel, React, Redux, React-Router. You can an example of this live at [www.reactrails.com](http://www.reactrails.com).
470
+ - [react\_on\_rails Gem](https://github.com/shakacode/react_on_rails): Integration of React with Rails utilizing Webpack, Babel, React, Redux, React-Router.
390
471
  - [Ruby Hyperloop](http://ruby-hyperloop.io/): Use Ruby to build reactive user interfaces with React.
391
472
  - [react-rails-hot-loader](https://github.com/rmosolgo/react-rails-hot-loader) is a simple live-reloader for `react-rails`.
392
473
  - [react-rails-benchmark_renderer](https://github.com/pboling/react-rails-benchmark_renderer) adds performance instrumentation to server rendering.
@@ -396,5 +477,4 @@ Any subclass of `ExecJSRenderer` may use those hooks (for example, `SprocketsRen
396
477
 
397
478
  - Run tests with `rake test` or `appraisal rake test`
398
479
  - Update React assets with `rake react:update`
399
-
400
- [React Getting Started]: https://facebook.github.io/react/docs/getting-started.html
480
+ - Update the UJS with `rake ujs:update`