Skip to content

Commit eeb4e6b

Browse files
author
Robert Mosolgo
committed
Merge pull request #191 from rmosolgo/readme-shuffle
chore(docs) reorganize readme
2 parents dfb371f + b269b16 commit eeb4e6b

File tree

1 file changed

+106
-198
lines changed

1 file changed

+106
-198
lines changed

README.md

Lines changed: 106 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,17 @@
1313
1414
> ***Additionally: `0.x` branch directly follows React versions, `1.x` will not do so.***
1515
16-
react-rails is a ruby gem which makes it easier 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 application.
16+
`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.1+) application. `react-rails` can:
1717

18-
19-
1. Making it easy to include `react.js` as part of your dependencies in `application.js`.
20-
2. Transforming JSX into regular JS on request, or as part of asset precompilation.
21-
3. View helpers to render React components in an unobtrusive style and/or on the server.
18+
- Provide [various `react` builds](#reactjs-builds) to your asset bundle
19+
- Transform [`.jsx` in the asset pipeline](#jsx)
20+
- [Render components into views and mount them](#rendering--mounting) via view helper & `react_ujs`
21+
- [Render components server-side](#server-rendering) with `prerender: true`.
22+
- [Generate components](#component-generator) with a Rails generator
2223

2324
## Installation
2425

25-
We're specifically targeting versions of Ruby on Rails which make use of the asset pipeline, which means Rails 3.1+.
26-
27-
As with all gem dependencies, we strongly recommend adding `react-rails` to your `Gemfile` and using `bundler` to manage your application's dependencies.
26+
Add `react-rails` to your gemfile:
2827

2928
```ruby
3029
# Gemfile
@@ -40,43 +39,51 @@ Next, run the installation script.
4039
rails g react:install
4140
```
4241

43-
This will require `react.js`, `react_ujs.js`, and a `components.js` manifest file in application.js, and create a directory named `app/assets/javascripts/components` for you to store React components in.
42+
This will:
43+
- create a `components.js` manifest file and a `app/assets/javascripts/components/` directory, where you will put your components
44+
- place the following in your `application.js`:
4445

45-
## Usage
46+
```js
47+
//= require react
48+
//= require react_ujs
49+
//= require components
50+
```
4651

47-
### react.js
52+
## Usage
4853

49-
In order to use React client-side in your application, you must make sure the browser requests it. One way to do that is to drop `react.js` into `vendor/assets/javascript/` and by default your application manifest will pick it up. There are downsides to this approach, so we made it even easier. Once you have `react-rails` installed, you can just add a line into your config file (see Configuring) and require react directly in your manifest:
54+
### React.js builds
5055

51-
You can `require` it in your manifest:
56+
You can pick which React.js build (development, production, with or without [add-ons]((http://facebook.github.io/react/docs/addons.html))) to serve in each environment by adding a config. Here are the defaults:
5257

53-
```js
54-
// app/assets/javascripts/application.js
58+
```ruby
59+
# config/environments/development.rb
60+
MyApp::Application.configure do
61+
config.react.variant = :development
62+
end
5563

56-
//= require react
64+
# config/environments/production.rb
65+
MyApp::Application.configure do
66+
config.react.variant = :production
67+
end
5768
```
5869

59-
Alternatively, you can include it directly as a separate script tag:
60-
61-
```erb
62-
# app/views/layouts/application.html.erb
70+
To include add-ons, use this config:
6371

64-
<%= javascript_include_tag "react" %>
72+
```ruby
73+
MyApp::Application.configure do
74+
config.react.addons = true # defaults to false
75+
end
6576
```
6677

67-
### JSX
78+
After restarting your Rails server, `//= require react` will provide the build of React.js which was specified by the configurations.
6879

69-
To transform your JSX into JS, simply create `.js.jsx` files. These files will be transformed on request, or precompiled as part of the `assets:precompile` task.
80+
In a pinch, you can also provide your own copies of React.js and JSXTransformer. Just add `react.js` or `JSXTransformer.js` (case-sensitive) files to `app/vendor/assets/javascripts/react/` and restart your development server. If you need different versions of React in different environments, put them in directories that match `config.react.variant`. For example, if you set `config.react.variant = :development`, you could put a copy of `react.js` in `/vendor/assets/react/development/`.
7081

71-
CoffeeScript files can also be used, by creating `.js.jsx.coffee` files. We also need to embed JSX inside backticks so CoffeeScript ignores the syntax it doesn't understand. Here's an example:
82+
### JSX
7283

73-
```coffee
74-
Component = React.createClass
75-
render: ->
76-
`<ExampleComponent videos={this.props.videos} />`
77-
```
84+
After installing `react-rails`, restart your server. Now, `.js.jsx` files will be transformed in the asset pipeline.
7885

79-
You can use the `--harmony` or `--strip-types` options by adding a configuration to `application.rb`:
86+
You can use JSX `--harmony` or `--strip-types` options by adding a configuration:
8087

8188
```ruby
8289
config.react.jsx_transform_options = {
@@ -85,145 +92,95 @@ You can use the `--harmony` or `--strip-types` options by adding a configuration
8592
}
8693
```
8794

88-
### Unobtrusive JavaScript
89-
90-
`react_ujs` will call `React.render` for every element with `data-react-class` attribute. React properties can be specified by `data-react-props` attribute in JSON format. For example:
95+
To use CoffeeScript, create `.js.jsx.coffee` files and embed JSX inside backticks, for example:
9196

92-
```erb
93-
<!-- react_ujs will execute `React.render(HelloMessage({name:"Bob"}), element)` -->
94-
<div data-react-class="HelloMessage" data-react-props="<%= {name: 'Bob'}.to_json %>" />
97+
```coffee
98+
Component = React.createClass
99+
render: ->
100+
`<ExampleComponent videos={this.props.videos} />`
95101
```
96102

97-
`react_ujs` will also scan DOM elements and call `React.unmountComponentAtNode` on page unload. If you want to disable this behavior, remove `data-react-class` attribute in `componentDidMount`.
98-
99-
To use `react_ujs`, simply `require` it after `react` (and after `turbolinks` if [Turbolinks](https://github.com/rails/turbolinks) is used).
103+
### Rendering & mounting
100104

101-
**Note:** _Turbolinks >= 2.4.0 is recommended. For older versions `react_ujs` will disable the Turbolinks cache to ensure components are correctly unmounted. See [#87](https://github.com/reactjs/react-rails/issues/87) for details._
105+
`react-rails` includes a view helper (`react_component`) and an unobtrusive JavaScript driver (`react_ujs`) which work together to put React components on the page. You should require the UJS driver in your manifest after `react` (and after `turbolinks` if you use [Turbolinks](https://github.com/rails/turbolinks))
102106

103-
```js
104-
// app/assets/javascripts/application.js
107+
The __view helper__ puts a `div` on the page with the requested component class & props. For example:
105108

106-
//= require turbolinks
107-
//= require react
108-
//= require react_ujs
109+
```erb
110+
<%= react_component('HelloMessage', name: 'John') %>
111+
<!-- becomes: -->
112+
<div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}"></div>
109113
```
110114

111-
### View helper
112-
113-
There is a view helper method `react_component`. It is designed to work with `react_ujs` and takes a React class name, properties, and HTML options as arguments:
115+
On page load, the __`react_ujs` driver__ will scan the page and mount components using `data-react-class` and `data-react-props`. Before page unload, it will unmount components (if you want to disable this behavior, remove `data-react-class` attribute in `componentDidMount`).
114116

115-
```ruby
116-
react_component('HelloMessage', name: 'John')
117-
# <div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}"></div>
118-
```
117+
`react_ujs` uses Turbolinks events if they're available, otherwise, it uses native events. __Turbolinks >= 2.4.0__ is recommended because it exposes better events.
119118

120-
By default, a `<div>` element is used. Other tag and HTML attributes can be specified:
119+
The view helper's signature is
121120

122121
```ruby
123-
react_component('HelloMessage', {name: 'John'}, :span)
124-
# <span data-...></span>
125-
126-
react_component('HelloMessage', {name: 'John'}, {id: 'hello', class: 'foo', tag: :span})
127-
# <span class="foo" id="hello" data-...></span>
122+
react_component(component_class_name, props={}, html_options={})
128123
```
129124

130-
#### With JSON and Jbuilder
131-
132-
You can pass prepared JSON directly to the helper, as well.
125+
- `component_class_name` is a string which names a globally-accessible component class. It may have dots (eg, `"MyApp.Header.MenuItem"`).
126+
- `props` is either an object that responds to `#to_json` or an already-stringified JSON object (eg, made with Jbuilder, see note below)
127+
- `html_options` may include:
128+
- `tag:` to use an element other than a `div` to embed `data-react-class` and `-props`.
129+
- `prerender: true` to render the component on the server.
130+
- `**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).
133131

134-
```ruby
135-
react_component('HelloMessage', {name: 'John'}.to_json)
136-
# <div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}"></div>
137-
```
138132

139-
This is especially helpful if you are already using a tool like Jbuilder in your project.
133+
### Server rendering
140134

141-
```ruby
142-
# messages/show.json.jbuilder
143-
json.name name
144-
```
135+
To render components on the server, pass `prerender: true` to `react_component`:
145136

146-
```ruby
147-
react_component('HelloMessage', render(template: 'messages/show.json.jbuilder', locals: {name: 'John'}))
148-
# <div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}"></div>
137+
```erb
138+
<%= react_component('HelloMessage', {name: 'John'}, {prerender: true}) %>
139+
<!-- becomes: -->
140+
<div data-react-class="HelloMessage" data-react-props="{&quot;name&quot;:&quot;John&quot;}">
141+
<h1>Hello, John!</h1>
142+
</div>
149143
```
150144

151-
##### Important Note
145+
_(It will be also be mounted by the UJS on page load.)_
152146

153-
By default, the scaffolded Rails index Jbuilder templates do not include a root node. An example scaffolded index.json.jbuilder looks like this:
154-
155-
```ruby
156-
json.array!(@messages) do |message|
157-
json.extract! message, :id, :name
158-
json.url message_url(http://github.com/message,%20%3Cspan%20class=%22pl-c1%22%3Eformat:%3C/span%3E%20%3Cspan%20class=%22pl-c1%22%3E:json%3C/span%3E)
159-
end
160-
```
147+
There are some requirements for this to work:
161148

162-
which generates JSON like this:
149+
- `react-rails` must load your code. By convention, it uses `components.js`, which was created by the install task. This file must include your components _and_ their dependencies (eg, Underscore.js).
150+
- Your components must be accessible in the global scope. If you are using `.js.jsx.coffee` files then the wrapper function needs to be taken into account:
163151

164-
```json
165-
[{"id":1,"name":"hello","url":"http://localhost:3000/messages/1.json"},{"id":2,"name":"hello","url":"http://localhost:3000/messages/2.json"},{"id":3,"name":"hello","url":"http://localhost:3000/messages/3.json"}]
166-
```
152+
```coffee
153+
# @ is `window`:
154+
@Component = React.createClass
155+
render: ->
156+
`<ExampleComponent videos={this.props.videos} />`
157+
```
158+
- Your code can't reference `document`. Prerender processes don't have access to `document`, so jQuery and some other libs won't work in this environment :(
167159

168-
However ReactJS expects the collection of props provided to a component to be a key-value object. Therefore, if you want to use your Jbuilder templates directly with the helper, you will need to wrap your index.json.jbuilder array with a root node like so:
160+
You can configure your pool of JS virtual machines and specify where it should load code:
169161

170162
```ruby
171-
json.messages(@messages) do |message|
172-
json.extract! message, :id, :name
173-
json.url message_url(http://github.com/message,%20%3Cspan%20class=%22pl-c1%22%3Eformat:%3C/span%3E%20%3Cspan%20class=%22pl-c1%22%3E:json%3C/span%3E)
163+
# config/environments/application.rb
164+
# These are the defaults if you dont specify any yourself
165+
MyApp::Application.configure do
166+
# renderer pool size:
167+
config.react.max_renderers = 10
168+
# prerender timeout, in seconds:
169+
config.react.timeout = 20
170+
# where to get React.js source:
171+
config.react.react_js = lambda { File.read(::Rails.application.assets.resolve('react.js')) }
172+
# array of filenames that will be requested from the asset pipeline
173+
# and concatenated:
174+
config.react.component_filenames = ['components.js']
175+
# server-side console.log, console.warn, and console.error messages will be replayed on the client
176+
# (you can set this to `true` in config/enviroments/development.rb to replay in development only)
177+
config.react.replay_console = false
174178
end
175179
```
176180

177-
Which will generate:
178-
179-
```json
180-
{"messages":[{"id":1,"name":"hello","url":"http://localhost:3000/messages/1.json"},{"id":2,"name":"hello","url":"http://localhost:3000/messages/2.json"},{"id":3,"name":"hello","url":"http://localhost:3000/messages/3.json"}]}
181-
```
182-
183-
### Server Rendering
181+
### Component generator
184182

185-
React components can also use the same ExecJS mechanisms in Sprockets to execute JavaScript code on the server, and render React components to HTML to be delivered to the browser, and then the `react_ujs` script will cause the component to be mounted. In this way, users get fast initial page loads and search-engine-friendly pages.
186-
187-
#### ExecJS
188-
189-
By default, ExecJS will use node.js in an external process to run JS code. Because we will be executing JS on the server in production, an in-process, high-performance JS VM should be used. Simply add the proper one for your platform to your Gemfile:
190-
191-
```ruby
192-
gem "therubyracer", :platforms => :ruby
193-
gem "therubyrhino", :platforms => :jruby
194-
```
195-
196-
#### components.js
197-
198-
In order for us to render your React components, we need to be able to find them and load them into the JS VM. By convention, we look for a `assets/javascripts/components.js` file through the asset pipeline, and load that. For example:
199-
200-
```sass
201-
// app/assets/javascripts/components.js
202-
//= require_tree ./components
203-
```
204-
205-
This will bring in all files located in the `app/assets/javascripts/components` directory. You can organize your code however you like, as long as a request for `/assets/javascripts/components.js` brings in a concatenated file containing all of your React components, and each one has to be available in the global scope (either `window` or `global` can be used). For `.js.jsx` files this is not a problem, but if you are using `.js.jsx.coffee` files then the wrapper function needs to be taken into account:
206-
207-
```coffee
208-
Component = React.createClass
209-
render: ->
210-
`<ExampleComponent videos={this.props.videos} />`
211-
212-
window.Component = Component
213-
```
214-
215-
#### View Helper
216-
217-
To take advantage of server rendering, use the same view helper `react_component`, and pass in `prerender: true` in the `options` hash.
218-
219-
```erb
220-
react_component('HelloMessage', {name: 'John'}, {prerender: true})
221-
```
222-
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.
223-
224-
### Component Generator
225-
226-
react-rails ships with a Rails generator to help you get started with a simple component scaffold. You can run it using `rails generate react:component ComponentName`. The generator takes an optional list of arguments for default propTypes, which follow the conventions set in the [Reusable Components](http://facebook.github.io/react/docs/reusable-components.html) section of the React documentation.
183+
react-rails ships with a Rails generator to help you get started with a simple component scaffold. You can run it using `rails generate react:component ComponentName`. The generator takes an optional list of arguments for default propTypes, which follow the conventions set in the [Reusable Components](http://facebook.github.io/react/docs/reusable-components.html) section of the React documentation.
227184

228185
For example:
229186

@@ -276,55 +233,24 @@ The following additional arguments have special behavior:
276233

277234
Note that the arguments for `oneOf` and `oneOfType` must be enclosed in single quotes to prevent your terminal from expanding them into an argument list.
278235

279-
## Configuring
280-
281-
### Variants
282-
283-
There are 2 variants available. `:development` gives you the unminified version of React. This provides extra debugging and error prevention. `:production` gives you the minified version of React which strips out comments and helpful warnings, and minifies.
284-
285-
```ruby
286-
# config/environments/development.rb
287-
MyApp::Application.configure do
288-
config.react.variant = :development
289-
end
290-
291-
# config/environments/production.rb
292-
MyApp::Application.configure do
293-
config.react.variant = :production
294-
end
295-
```
296-
297-
### Add-ons
236+
### Jbuilder & react-rails
298237

299-
Beginning with React v0.5, there is another type of build. This build ships with some "add-ons" that might be useful - [take a look at the React documentation for details](http://facebook.github.io/react/docs/addons.html). In order to make these available, we've added another configuration (which defaults to `false`).
238+
If you use Jbuilder to pass JSON string to `react_component`, make sure your JSON is a stringified hash, not an array. This is not the Rails default -- you should add the root node yourself. For example:
300239

301240
```ruby
302-
MyApp::Application.configure do
303-
config.react.addons = true
241+
# BAD: returns a stringified array
242+
json.array!(@messages) do |message|
243+
json.extract! message, :id, :name
244+
json.url message_url(http://github.com/message,%20%3Cspan%20class=%22pl-c1%22%3Eformat:%3C/span%3E%20%3Cspan%20class=%22pl-c1%22%3E:json%3C/span%3E)
304245
end
305-
```
306246

307-
### Server Rendering
308-
309-
For performance and thread-safety reasons, a pool of JS VMs are spun up on application start, and the size of the pool and the timeout on requesting a VM from the pool are configurable.
310-
311-
```ruby
312-
# config/environments/application.rb
313-
# These are the defaults if you dont specify any yourself
314-
MyApp::Application.configure do
315-
config.react.max_renderers = 10
316-
config.react.timeout = 20 #seconds
317-
config.react.react_js = lambda {File.read(::Rails.application.assets.resolve('react.js'))}
318-
config.react.component_filenames = ['components.js']
319-
config.react.replay_console = false
247+
# GOOD: returns a stringified hash
248+
json.messages(@messages) do |message|
249+
json.extract! message, :id, :name
250+
json.url message_url(http://github.com/message,%20%3Cspan%20class=%22pl-c1%22%3Eformat:%3C/span%3E%20%3Cspan%20class=%22pl-c1%22%3E:json%3C/span%3E)
320251
end
321252
```
322253

323-
Other configuration options include:
324-
* `react_js`: where you want to grab the javascript library from
325-
* `component_filenames`: an array of filenames that will be requested from the asset pipeline and concatenated together
326-
* `replay_console`: additional debugging by replaying any captured console messages from server-rendering back on the client (note: they will lose their call stack, but it can help point you in right direction)
327-
328254
## CoffeeScript
329255

330256
It is possible to use JSX with CoffeeScript. The caveat is that you will still need to include the docblock. Since CoffeeScript doesn't allow `/* */` style comments, we need to do something a little different. We also need to embed JSX inside backticks so CoffeeScript ignores the syntax it doesn't understand. Here's an example:
@@ -334,21 +260,3 @@ Component = React.createClass
334260
render: ->
335261
`<ExampleComponent videos={this.props.videos} />`
336262
```
337-
338-
### Changing react.js and JSXTransformer.js versions
339-
340-
In some cases you may want to have your `react.js` and `JSXTransformer.js` files come from a different release than the one, that is specified in the `react-rails.gemspec`. To achieve that, you have to manually replace them in your app.
341-
342-
#### Instructions
343-
344-
Just put another version of `react.js` or `JSXTransformer.js` under `/vendor/assets/react` directory.
345-
If you need different versions of `react.js` for production and development, then use a subdirectory named
346-
after `config.react.variant`, e.g. you set `config.react.variant = :development` so for this environment
347-
`react.js` is expected to be in `/vendor/assets/react/development`
348-
349-
#### Things to remember
350-
351-
If you replace `JSXTransformer.js` in production environment, you have to restart your rails instance,
352-
because the jsx compiler context is cached.
353-
354-
Name of the `JSXTransformer.js` file *is case-sensitive*.

0 commit comments

Comments
 (0)