react_on_rails 11.0.9 → 11.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +8 -2
- data/{docs/LICENSE.md → LICENSE.md} +1 -1
- data/README.md +177 -693
- data/SUMMARY.md +39 -26
- data/docs/additional-reading/convert-rails-5-api-only-app.md +19 -0
- data/docs/additional-reading/credits.md +10 -0
- data/docs/additional-reading/rails-assets-relative-paths.md +2 -2
- data/docs/additional-reading/server-rendering-tips.md +2 -4
- data/docs/additional-reading/webpack.md +2 -2
- data/docs/api/javascript-api.md +21 -1
- data/docs/api/redux-store-api.md +100 -0
- data/docs/api/view-helpers-api.md +115 -0
- data/docs/articles.md +20 -0
- data/docs/basics/client-vs-server-rendering.md +17 -0
- data/docs/basics/deployment.md +6 -0
- data/docs/basics/{generator.md → generator-details.md} +4 -7
- data/docs/basics/generator-functions-and-railscontext.md +157 -0
- data/docs/basics/how-react-on-rails-works.md +40 -0
- data/docs/basics/installation-into-an-existing-rails-app.md +64 -0
- data/docs/basics/react-server-rendering.md +27 -0
- data/docs/{additional-reading → basics}/recommended-project-structure.md +26 -4
- data/docs/{additional-reading → basics}/rspec-configuration.md +0 -0
- data/docs/basics/webpack-configuration.md +29 -0
- data/docs/misc/doctrine.md +1 -1
- data/docs/{additional-reading → misc-pending}/code-splitting.md +8 -2
- data/docs/{basics/installation-overview.md → misc-pending/manual-installation-overview.md} +3 -8
- data/docs/{additional-reading → misc-pending}/rails-assets.md +3 -1
- data/docs/testimonials.md +11 -0
- data/docs/tutorial.md +4 -4
- data/lib/generators/USAGE +1 -1
- data/lib/react_on_rails/{react_on_rails_helper.rb → helper.rb} +4 -4
- data/lib/react_on_rails/prerender_error.rb +7 -3
- data/lib/react_on_rails/server_rendering_pool.rb +0 -1
- data/lib/react_on_rails/utils.rb +17 -0
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails.rb +1 -1
- data/package.json +1 -1
- data/react_on_rails.gemspec +1 -1
- metadata +27 -17
- data/docs/additional-reading/caching-and-performance.md +0 -4
- data/docs/additional-reading/node-server-rendering.md +0 -5
- data/docs/api/ruby-api.md +0 -8
data/SUMMARY.md
CHANGED
@@ -1,50 +1,63 @@
|
|
1
|
-
# Table of
|
1
|
+
# Table of Contents
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
+ [Home](./README.md)
|
4
|
+
|
5
|
+
## **Basics**
|
6
|
+
+ [React on Rails Basic Installation Tutorial](./docs/tutorial.md)
|
7
|
+
+ [Webpack Configuration](./docs/basics/webpack-configuration.md)
|
8
|
+
+ [How React on Rails Works](./docs/basics/how-react-on-rails-works.md)
|
9
|
+
+ [Recommended Project Structure](./docs/basics/recommended-project-structure.md)
|
10
|
+
+ [Generator Functions and the RailsContext](docs/basics/generator-functions-and-railscontext.md)
|
11
|
+
+ [Caching and Performance: React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki).
|
12
|
+
+ [Deployment](docs/basics/deployment.md).
|
13
|
+
+ [React on Rails Internationalization (I18n, localization)](docs/basics/i18n.md)
|
14
|
+
+ [RSpec Test Helpers Configuration](docs/basics/rspec-configuration.md)
|
15
|
+
+ [Upgrading React on Rails](docs/basics/upgrading-react-on-rails.md)
|
16
|
+
|
17
|
+
## **API**
|
18
|
+
- [View Helpers API](./docs/api/view-helpers-api.md)
|
19
|
+
- [JavaScript API](./docs/api/javascript-api.md)
|
20
|
+
- [Redux Store API](./docs/api/redux-store-api.md)
|
21
|
+
|
22
|
+
## **Additional Details**
|
23
|
+
+ [Migration from react-rails](./docs/basics/migrating-from-react-rails.md)
|
24
|
+
+ [Generator Details](docs/basics/generator-details.md)
|
25
|
+
+ [Updating Dependencies](./docs/additional-reading/updating-dependencies.md)
|
26
|
+
+ [Manual Installation Overview](docs/misc-pending/manual-installation-overview.md)
|
27
|
+
|
28
|
+
## **Rails**
|
5
29
|
+ [Rails Engine Integration](./docs/additional-reading/rails-engine-integration.md)
|
6
30
|
+ [Rails View Rendering from Inline JavaScript](./docs/additional-reading/rails_view_rendering_from_inline_javascript.md)
|
7
|
-
+ [RSpec Configuration](./docs/additional-reading/rspec-configuration.md)
|
8
31
|
+ [Turbolinks](./docs/additional-reading/turbolinks.md)
|
9
|
-
+ [
|
32
|
+
+ [Rails Assets](docs/misc-pending/rails-assets.md)
|
33
|
+
+ [Converting a Rails 5 API only app to a Rails app](./docs/additional-reading/convert-rails-5-api-only-app.md)
|
10
34
|
|
11
|
-
|
35
|
+
## **Javascript**
|
12
36
|
+ [Node Dependencies, NPM, and Yarn](./docs/additional-reading/node-dependencies-and-npm.md)
|
13
37
|
+ [Babel](./docs/additional-reading/babel.md)
|
14
38
|
+ [React Router](./docs/additional-reading/react-router.md)
|
15
39
|
+ [React & Redux](./docs/additional-reading/react-and-redux.md)
|
16
|
-
+ [Webpack](./docs/additional-reading/webpack.md)
|
17
|
-
+ [Webpack Configuration](./docs/additional-reading/webpack.md)
|
18
|
-
+ [Webpack Cookbook](https://christianalfoni.github.io/react-webpack-cookbook/index.html)
|
19
|
-
+ [Developing with the Webpack Dev Server](docs/additional-reading/webpack-dev-server.md)
|
20
|
-
+ [Node Server Rendering](./docs/additional-reading/node-server-rendering.md)
|
40
|
+
+ [Webpack Tips](./docs/additional-reading/webpack-tips.md)
|
21
41
|
+ [Server Rendering Tips](./docs/additional-reading/server-rendering-tips.md)
|
22
|
-
+ [Code Splitting](
|
42
|
+
+ [Code Splitting](docs/misc-pending/code-splitting.md)
|
23
43
|
+ [AngularJS Integration and Migration to React on Rails](./docs/additional-reading/angular-js-integration-migration.md)
|
24
|
-
+ [Webpack, the Asset Pipeline, and Using Assets w/ React](./docs/additional-reading/rails-assets-relative-paths.md)
|
25
44
|
|
26
|
-
|
27
|
-
+ [React on Rails Basic Installation Tutorial](./docs/tutorial.md)
|
28
|
-
+ [Installation Overview](./docs/basics/installation-overview.md)
|
29
|
-
+ [Migration from react-rails](./docs/basics/migrating-from-react-rails.md)
|
30
|
-
+ [Recommended Project Structure](./docs/additional-reading/recommended-project-structure.md)
|
31
|
-
+ [Generator Tips](./docs/basics/generator.md)
|
32
|
-
+ [Hot Reloading of Assets For Rails Development](./docs/additional-reading/hot-reloading-rails-development.md)
|
45
|
+
## **Deployment**
|
33
46
|
+ [Heroku Deployment](./docs/additional-reading/heroku-deployment.md)
|
34
47
|
+ [Elastic Beanstalk Deployment](./docs/additional-reading/elastic-beanstalk.md)
|
35
|
-
+ [Updating Dependencies](./docs/additional-reading/updating-dependencies.md)
|
36
48
|
|
37
|
-
|
38
|
-
+ [JavaScript API](./docs/api/javascript-api.md)
|
39
|
-
+ [Ruby API](./docs/api/ruby-api.md)
|
49
|
+
## Older, Non-Webpack Docs
|
40
50
|
+ [Setting up Hot Reloading during Rails Development, API docs](./docs/api/ruby-api-hot-reload-view-helpers.md)
|
51
|
+
+ [Developing with the Webpack Dev Server](./docs/additional-reading/webpack-dev-server.md)
|
52
|
+
+ [Webpack, the Asset Pipeline, and Using Assets w/ React](./docs/additional-reading/rails-assets-relative-paths.md)
|
53
|
+
+ [Hot Reloading of Assets For Rails Development](./docs/additional-reading/hot-reloading-rails-development.md)
|
41
54
|
|
42
|
-
|
55
|
+
## **[CONTRIBUTING](CONTRIBUTING.md)**
|
43
56
|
+ [Generator Testing](./docs/contributor-info/generator-testing.md)
|
44
57
|
+ [Linting](./docs/contributor-info/linters.md)
|
45
58
|
+ [Releasing](./docs/contributor-info/releasing.md)
|
46
59
|
|
47
|
-
|
60
|
+
## **Misc**
|
48
61
|
+ [Tips](./docs/additional-reading/tips.md)
|
49
62
|
+ [Changelog](./CHANGELOG.md)
|
50
63
|
+ [Projects](./PROJECTS.md)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Convert Rails 5 API only app to a Rails app
|
2
|
+
|
3
|
+
1. Go to the directory where you created your app
|
4
|
+
|
5
|
+
```bash
|
6
|
+
$ rails new your-current-app-name
|
7
|
+
```
|
8
|
+
|
9
|
+
Rails will start creating the app and will skip the files you have already created. If there is some conflict then it will stop and you need to resolve it manually. be careful at this step as it might replace you current code in conflicted files.
|
10
|
+
|
11
|
+
2. Resolve conflicts
|
12
|
+
|
13
|
+
```
|
14
|
+
1. Press "d" to see the difference
|
15
|
+
2. If it is only adding lines then press "y" to continue
|
16
|
+
3. If it is removeing some of your code then press "n" and add all additions manually
|
17
|
+
```
|
18
|
+
|
19
|
+
3. Run `bundle install` and follow [the instructions for installing into an existing Rails app](../basics/installation-into-an-existing-rails-app.md).*
|
@@ -0,0 +1,10 @@
|
|
1
|
+
## Authors
|
2
|
+
|
3
|
+
[The Shaka Code team!](http://www.shakacode.com/about/)
|
4
|
+
|
5
|
+
The origins of the project began with the need to do a rich JavaScript interface for a ShakaCode's client. The choice to use Webpack and Rails is described in [Fast Rich Client Rails Development With Webpack and the ES6 Transpiler](http://www.railsonmaui.com/blog/2014/10/03/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/).
|
6
|
+
|
7
|
+
The gem project started with [Justin Gordon](https://github.com/justin808/) pairing with [Samnang Chhun](https://github.com/samnang) to figure out how to do server rendering with Webpack plus Rails. [Alex Fedoseev](https://github.com/alexfedoseev) then joined in. [Rob Wise](https://github.com/robwise), [Aaron Van Bokhoven](https://github.com/aaronvb), and [Andy Wang](https://github.com/yorzi) did the bulk of the generators. Many others have [contributed](https://github.com/shakacode/react_on_rails/graphs/contributors).
|
8
|
+
|
9
|
+
The gem was initially inspired by the [react-rails gem](https://github.com/reactjs/react-rails).
|
10
|
+
|
@@ -77,7 +77,7 @@ Note: _You can output these files in the asset pipeline wherever you see fit. My
|
|
77
77
|
|
78
78
|
Lastly, we will set the publicPath to our file(s). This will be the endpoint on our rails web server that you can visit to reach the asset (if you don't know how this works, read the [intro](#using-webpack-bundled-assets-with-the-rails-asset-pipeline)). If you've been following the previous steps, you know that we set our outputPath for our assets to be absolute at `app/assets/webpack/webpack-assets/`, which your rails app should end up hosting at `/assets/webpack-assets/file-name+hash.ext` when the server is run.
|
79
79
|
|
80
|
-
Note: _If you're having a hard time figuring out what an asset's path will be on your rails server, simply run `rake assets:precompile` and `cd public/`. The path from there to your file will then be the path/url on your web server to that asset. On top of this, it is also a good idea to check out [this doc](
|
80
|
+
Note: _If you're having a hard time figuring out what an asset's path will be on your rails server, simply run `rake assets:precompile` and `cd public/`. The path from there to your file will then be the path/url on your web server to that asset. On top of this, it is also a good idea to check out [this doc](../misc-pending/rails-assets.md) to understand how `react_on_rails` allows us to access these files after precompilation, when Rails applies another hash onto the asset._
|
81
81
|
|
82
82
|
Our publicPath setting will match the path to our outputted assets on our rails web server. Given our assets in this example will be outputted to `/app/assets/webpack/webpack-assets/` and hosted at `/assets/webpack-assets/`, our publicPath would be:
|
83
83
|
|
@@ -192,4 +192,4 @@ module.exports = {
|
|
192
192
|
};
|
193
193
|
```
|
194
194
|
|
195
|
-
If you'd like to understand how react_on_rails handles these bundled assets after asset precompilation and in production mode, check out: [Rails Assets](
|
195
|
+
If you'd like to understand how react_on_rails handles these bundled assets after asset precompilation and in production mode, check out: [Rails Assets](../misc-pending/rails-assets.md).
|
@@ -9,10 +9,8 @@ Be sure to use mini_racer. See [issues/428](https://github.com/shakacode/react_o
|
|
9
9
|
- You can conditionally avoid running code that references document by passing in a boolean prop to your top level react
|
10
10
|
component. Since the passed in props Hash from the view helper applies to client and server side code, the best way to
|
11
11
|
do this is to use a generator function.
|
12
|
-
- If you're serious about server rendering, it's worth the effort to have different entry points for client and server rendering. It's worth the extra complexity.
|
13
|
-
- You can enable
|
14
|
-
|
15
|
-
The point is that you have separate files for top level client or server side, and you pass some extra option indicating that rendering is happening server side.
|
12
|
+
- If you're serious about server rendering, it's worth the effort to have different entry points for client and server rendering. It's worth the extra complexity. The point is that you have separate files for top level client or server side, and you pass some extra option indicating that rendering is happening server side.
|
13
|
+
- You can enable Node.js server rendering via [React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki).
|
16
14
|
|
17
15
|
## Troubleshooting Server Rendering
|
18
16
|
|
@@ -18,5 +18,5 @@ Webpack v2 makes this very convenient! See:
|
|
18
18
|
* [Implicit Common Vendor Chunk](https://webpack.js.org/guides/code-splitting-libraries/#implicit-common-vendor-chunk)
|
19
19
|
* [Manifest File](https://webpack.js.org/guides/code-splitting-libraries/#manifest-file)
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
## Webpack v4
|
22
|
+
Webpack v4 is heartily recommended. If you need help with migrating your project to Webpack v4, please contact me, [justin@shakacode.com](mailto:justin@shakacode.com).
|
data/docs/api/javascript-api.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# ReactOnRails JavaScript API
|
2
|
-
|
2
|
+
## CSRF protection
|
3
|
+
|
4
|
+
Rails has built-in protection for Cross-Site Request Forgery (CSRF), see [Rails Documentation](http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf). To nicely utilize this feature in JavaScript requests, React on Rails provides two helpers that can be used as following for POST, PUT or DELETE requests:
|
5
|
+
|
6
|
+
```js
|
7
|
+
import ReactOnRails from 'react-on-rails';
|
8
|
+
|
9
|
+
// reads from DOM csrf token generated by Rails in <%= csrf_meta_tags %>
|
10
|
+
csrfToken = ReactOnRails.authenticityToken();
|
11
|
+
|
12
|
+
// compose Rails specific request header as following { X-CSRF-Token: csrfToken, X-Requested-With: XMLHttpRequest }
|
13
|
+
header = ReactOnRails.authenticityHeaders(otherHeader);
|
14
|
+
```
|
15
|
+
|
16
|
+
If you are using [jquery-ujs](https://github.com/rails/jquery-ujs) for AJAX calls, then these helpers are not needed because the [jquery-ujs](https://github.com/rails/jquery-ujs) library updates header automatically, see [jquery-ujs documentation](https://robots.thoughtbot.com/a-tour-of-rails-jquery-ujs#cross-site-request-forgery-protection).
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
## API
|
21
|
+
|
22
|
+
The best source of docs is the main [ReactOnRails.js](https://github.com/shakacode/react_on_rails/node_package/src/ReactOnRails.js) file. Here's a quick summary. No guarantees that this won't be outdated!
|
3
23
|
|
4
24
|
```js
|
5
25
|
/**
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# Redux Store
|
2
|
+
|
3
|
+
First things first. You don't need to use the `redux_store` api to use redux. This api was setup to support multiple calls to `react_component` on one page that all talk to the same redux store.
|
4
|
+
|
5
|
+
If you are only rendering one react component on a page, as is typical to do a "Single Page App" in React, then you should _probably_ pass the props to your React component in a "generator function."
|
6
|
+
|
7
|
+
Consider using the `redux_store` helper for the two following use cases:
|
8
|
+
|
9
|
+
1. You want to have multiple React components accessing the same store at once.
|
10
|
+
2. You want to place the props to hydrate the client side stores at the very end of your HTML, probably server rendered, so that the browser can render all earlier HTML first. This is particularly useful if your props will be large. However, you're probably better off using [React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki) if you're at all concerned about performance.
|
11
|
+
|
12
|
+
## Multiple React Components on a Page with One Store
|
13
|
+
|
14
|
+
You may wish to have 2 React components share the same the Redux store. For example, if your navbar is a React component, you may want it to use the same store as your component in the main area of the page. You may even want multiple React components in the main area, which allows for greater modularity. Also, you may want this to work with Turbolinks to minimize reloading the JavaScript.
|
15
|
+
|
16
|
+
A good example of this would be something like a notifications counter in a header. As each notification is read in the body of the page, you would like to update the header. If both the header and body share the same Redux store, then this is trivial. Otherwise, we have to rely on other solutions, such as the header polling the server to see how many unread notifications exist.
|
17
|
+
|
18
|
+
Suppose the Redux store is called `appStore`, and you have 3 React components that each needs to connect to a store: `NavbarApp`, `CommentsApp`, and `BlogsApp`. I named them with `App` to indicate that they are the registered components.
|
19
|
+
|
20
|
+
You will need to make a function that can create the store you will be using for all components and register it via the `registerStore` method. Note: this is a **storeCreator**, meaning that it is a function that takes (props, location) and returns a store:
|
21
|
+
|
22
|
+
```js
|
23
|
+
function appStore(props, railsContext) {
|
24
|
+
// Create a hydrated redux store, using props and the railsContext (object with
|
25
|
+
// Rails contextual information).
|
26
|
+
return myAppStore;
|
27
|
+
}
|
28
|
+
|
29
|
+
ReactOnRails.registerStore({
|
30
|
+
appStore
|
31
|
+
});
|
32
|
+
```
|
33
|
+
|
34
|
+
When registering your component with React on Rails, you can get the store via `ReactOnRails.getStore`:
|
35
|
+
|
36
|
+
```js
|
37
|
+
// getStore will initialize the store if not already initialized, so creates or retrieves store
|
38
|
+
const appStore = ReactOnRails.getStore("appStore");
|
39
|
+
return (
|
40
|
+
<Provider store={appStore}>
|
41
|
+
<CommentsApp />
|
42
|
+
</Provider>
|
43
|
+
);
|
44
|
+
```
|
45
|
+
|
46
|
+
From your Rails view, you can use the provided helper `redux_store(store_name, props)` to create a fresh version of the store (because it may already exist if you came from visiting a previous page). Note: for this example, since we're initializing this from the main layout, we're using a generic name of `@react_props`. In other words, the Rails controller would set `@react_props` to the properties to hydrate the Redux store.
|
47
|
+
|
48
|
+
**app/views/layouts/application.html.erb**
|
49
|
+
|
50
|
+
```erb
|
51
|
+
...
|
52
|
+
<%= redux_store("appStore", props: @react_props) %>;
|
53
|
+
<%= react_component("NavbarApp") %>
|
54
|
+
yield
|
55
|
+
...
|
56
|
+
```
|
57
|
+
|
58
|
+
Components should be created as [stateless function(al) components](https://facebook.github.io/react/docs/reusable-components.html#stateless-functions). Since you can pass in initial props via the helper `redux_store`, you do not need to pass any props directly to the component. Instead, the component hydrates by connecting to the store.
|
59
|
+
|
60
|
+
**_comments.html.erb**
|
61
|
+
|
62
|
+
```erb
|
63
|
+
<%= react_component("CommentsApp") %>
|
64
|
+
```
|
65
|
+
|
66
|
+
**_blogs.html.erb**
|
67
|
+
|
68
|
+
```erb
|
69
|
+
<%= react_component("BlogsApp") %>
|
70
|
+
```
|
71
|
+
|
72
|
+
*Note:* You will not be doing any partial updates to the Redux store when loading a new page. When the page content loads, React on Rails will rehydrate a new version of the store with whatever props are placed on the page.
|
73
|
+
|
74
|
+
## Controller Extension
|
75
|
+
|
76
|
+
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:
|
77
|
+
|
78
|
+
`redux_store(store_name, props: {})`
|
79
|
+
|
80
|
+
- **store_name:** A name for the store. You'll refer to this name in 2 places in your JavaScript:
|
81
|
+
1. You'll call `ReactOnRails.registerStore({storeName})` in the same place that you register your components.
|
82
|
+
2. In your component definition, you'll call `ReactOnRails.getStore('storeName')` to get the hydrated Redux store to attach to your components.
|
83
|
+
- **props:** Named parameter `props`. ReactOnRails takes care of setting up the hydration of your store with props from the view.
|
84
|
+
|
85
|
+
For an example, see [spec/dummy/app/controllers/pages_controller.rb](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/app/controllers/pages_controller.rb). Note: this is preferable to using the equivalent view_helper `redux_store` in that you can be assured that the store is initialized before your components.
|
86
|
+
|
87
|
+
## View Helper
|
88
|
+
|
89
|
+
`redux_store(store_name, props: {})`
|
90
|
+
|
91
|
+
This method has the same API as the controller extension. **HOWEVER**, we recommend the controller extension instead because the Rails executes the template code in the controller action's view file (`erb`, `haml`, `slim`, etc.) before the layout. So long as you call `redux_store` at the beginning of your action's view file, this will work. However, it's an easy mistake to put this call in the wrong place. Calling `redux_store` in the controller action ensures proper load order, regardless of where you call this in the controller action. Note: you won't know of this subtle ordering issue until you server render and you find that your store is not hydrated properly.
|
92
|
+
|
93
|
+
`redux_store_hydration_data`
|
94
|
+
|
95
|
+
Place this view helper (no parameters) at the end of your shared layout so ReactOnRails will render the redux store hydration data. Since we're going to be setting up the stores in the controllers, we need to know where on the view to put the client-side rendering of this hydration data, which is a hidden div with a matching class that contains a data props. For an example, see [spec/dummy/app/views/layouts/application.html.erb](https://github.com/shakacode/react_on_rails/tree/master/spec/dummy/app/views/layouts/application.html.erb).
|
96
|
+
|
97
|
+
# More Details
|
98
|
+
|
99
|
+
* [lib/react_on_rails/controller.rb](../../lib/react_on_rails/controller.rb) source
|
100
|
+
* [lib/react_on_rails/helper.rb](../../lib/react_on_rails/helper.rb) source
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# View and Controller Helpers
|
2
|
+
## View Helpers API
|
3
|
+
|
4
|
+
Once the bundled files have been generated in your `app/assets/webpack` folder and you have registered your components, you will want to render these components on your Rails views using the included helper method, `react_component`.
|
5
|
+
|
6
|
+
### react_component
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
react_component(component_name,
|
10
|
+
props: {},
|
11
|
+
prerender: nil,
|
12
|
+
trace: nil,
|
13
|
+
replay_console: nil,
|
14
|
+
raise_on_prerender_error: nil,
|
15
|
+
id: nil,
|
16
|
+
html_options: {})
|
17
|
+
```
|
18
|
+
|
19
|
+
- **component_name:** Can be a React component, created using an ES6 class or a generator function that returns a React component (or, only on the server side, an object with shape { redirectLocation, error, renderedHtml }), or a "renderer function" that manually renders a React component to the dom (client side only).
|
20
|
+
All options except `props, id, html_options` will inherit from your `react_on_rails.rb` initializer, as described [here](../basics/configuration.md).
|
21
|
+
- **general options:**
|
22
|
+
- **props:** Ruby Hash which contains the properties to pass to the react object, or a JSON string. If you pass a string, we'll escape it for you.
|
23
|
+
- **prerender:** enable server-side rendering of a component. Set to false when debugging!
|
24
|
+
- **id:** Id for the div, will be used to attach the React component. This will get assigned automatically if you do not provide an id. Must be unique.
|
25
|
+
- **html_options:** Any other HTML options get placed on the added div for the component. For example, you can set a class (or inline style) on the outer div so that it behaves like a span, with the styling of `display:inline-block`.
|
26
|
+
- **trace:** set to true to print additional debugging information in the browser. Defaults to true for development, off otherwise. Only on the **client side** will you will see the `railsContext` and your props.
|
27
|
+
- **options if prerender (server rendering) is true:**
|
28
|
+
- **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.
|
29
|
+
- **logging_on_server:** Default is true. True will log JS console messages and errors to the server.
|
30
|
+
- **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.
|
31
|
+
|
32
|
+
|
33
|
+
### react_component_hash
|
34
|
+
|
35
|
+
`react_component_hash` is used to return multiple HTML strings for server rendering, such as for
|
36
|
+
adding meta-tags to a page. It is exactly like react_component except for the following:
|
37
|
+
|
38
|
+
1. `prerender: true` is automatically added to options, as this method doesn't make sense for
|
39
|
+
client only rendering.
|
40
|
+
2. Your JavaScript for server rendering must return an Object for the key `server_rendered_html`.
|
41
|
+
3. Your view code must expect an object and not a string.
|
42
|
+
|
43
|
+
Here is an example of ERB view code:
|
44
|
+
|
45
|
+
```erb
|
46
|
+
<% react_helmet_app = react_component_hash("ReactHelmetApp", prerender: true,
|
47
|
+
props: { helloWorldData: { name: "Mr. Server Side Rendering"}},
|
48
|
+
id: "react-helmet-0", trace: true) %>
|
49
|
+
<% content_for :title do %>
|
50
|
+
<%= react_helmet_app['title'] %>
|
51
|
+
<% end %>
|
52
|
+
<%= react_helmet_app["componentHtml"] %>
|
53
|
+
```
|
54
|
+
|
55
|
+
And here is the JavaScript code:
|
56
|
+
|
57
|
+
```js
|
58
|
+
export default (props, _railsContext) => {
|
59
|
+
const componentHtml = renderToString(<ReactHelmet {...props} />);
|
60
|
+
const helmet = Helmet.renderStatic();
|
61
|
+
|
62
|
+
const renderedHtml = {
|
63
|
+
componentHtml,
|
64
|
+
title: helmet.title.toString(),
|
65
|
+
};
|
66
|
+
return { renderedHtml };
|
67
|
+
};
|
68
|
+
|
69
|
+
```
|
70
|
+
|
71
|
+
### cached_react_component and cached_react_component_hash
|
72
|
+
Fragment caching is a [React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki) feature. The API is the same as the above, but for 2 differences:
|
73
|
+
|
74
|
+
1. The `cache_key` takes the same parameters as any Rails `cache` view helper.
|
75
|
+
1. The **props** are passed via a block so that evaluation of the props is not done unless the cache is broken. Suppose you put your props calculation into some method called `some_slow_method_that_returns_props`:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
<%= cached_react_component("App", cache_key: [@user, @post], prerender: true) do
|
79
|
+
some_slow_method_that_returns_props
|
80
|
+
end %>
|
81
|
+
```
|
82
|
+
### rails_context
|
83
|
+
|
84
|
+
You can call `rails_context(server_side: true | false)` from your controller or view to see what values are are in the Rails Context. Pass true or false depending on whether you want to see the server side or the client side rails_context.
|
85
|
+
|
86
|
+
|
87
|
+
### Renderer Functions (function that will call ReactDOM.render or ReactDOM.hydrate)
|
88
|
+
|
89
|
+
A "renderer function" is a generator function that accepts three arguments (rather than 2): `(props, railsContext, domNodeId) => { ... }`. Instead of returning a React component, a renderer is responsible for installing a callback that will call `ReactDOM.render` (in React 16+, `ReactDOM.hydrate`) to render a React component into the DOM. The "renderer function" is called at the same time the document ready event would instantate the React components into the DOM.
|
90
|
+
|
91
|
+
Why would you want to call `ReactDOM.hydrate` yourself? One possible use case is [code splitting](../misc-pending/code-splitting.md). In a nutshell, you don't want to load the React component on the DOM node yet. So you want to install some handler that will call `ReactDOM.hydrate` at a later time. In the case of code splitting with server rendering, the server rendered code has any async code loaded and used to server render. Thus, the client code must also fully load any asynch code before server rendering. Otherwise, the client code would first render partially, not matching the server rendering, and then a second later, the full code would render, resulting in an unpleasant flashing on the screen.
|
92
|
+
|
93
|
+
Renderer functions are not meant to be used on the server since there's no DOM on the server. Instead, use a generator function. Attempting to server render with a renderer function will throw an error.
|
94
|
+
|
95
|
+
### React Router
|
96
|
+
|
97
|
+
[React Router](https://github.com/reactjs/react-router) is supported, including server-side rendering! See:
|
98
|
+
|
99
|
+
1. [React on Rails docs for react-router](../additional-reading/react-router.md)
|
100
|
+
2. Examples in [spec/dummy/app/views/react_router](../../spec/dummy/app/views/react_router) and follow to the JavaScript code in the [spec/dummy/client/app/startup/ServerRouterApp.jsx](../../spec/dummy/client/app/startup/ServerRouterApp.jsx).
|
101
|
+
3. [Code Splitting docs](../misc-pending/code-splitting.md) for information about how to set up code splitting for server rendered routes.
|
102
|
+
|
103
|
+
## server_render_js
|
104
|
+
|
105
|
+
`server_render_js(js_expression, options = {})`
|
106
|
+
|
107
|
+
- js_expression, like 2 + 3, and not a block of js code. If you have more than one line that needs to be executed, wrap it in an [IIFE](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression). JS exceptions will be caught, and console messages will be handled properly
|
108
|
+
- Currently, the only option you may pass is `replay_console` (boolean)
|
109
|
+
|
110
|
+
This is a helper method that takes any JavaScript expression and returns the output from evaluating it. If you have more than one line that needs to be executed, wrap it in an IIFE. JS exceptions will be caught and console messages handled properly.
|
111
|
+
|
112
|
+
# More details
|
113
|
+
|
114
|
+
See the [lib/react_on_rails/helper.rb](../../lib/react_on_rails/helper.rb) source.
|
115
|
+
|
data/docs/articles.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Articles, Videos, and Podcasts
|
2
|
+
|
3
|
+
## Articles
|
4
|
+
|
5
|
+
* [Introducing React on Rails v9 with Webpacker Support](https://blog.shakacode.com/introducing-react-on-rails-v9-with-webpacker-support-f2584c6c8fa4) for an overview of the integration of React on Rails with Webpacker.
|
6
|
+
* [Webpacker Lite: Why Fork Webpacker?](https://blog.shakacode.com/webpacker-lite-why-fork-webpacker-f0a7707fac92)
|
7
|
+
* [React on Rails, 2000+ 🌟 Stars](https://medium.com/shakacode/react-on-rails-2000-stars-32ff5cfacfbf#.6gmfb2gpy)
|
8
|
+
* [The React on Rails Doctrine](https://medium.com/@railsonmaui/the-react-on-rails-doctrine-3c59a778c724)
|
9
|
+
* [Simple Tutorial](docs/tutorial.md).
|
10
|
+
|
11
|
+
## Videos
|
12
|
+
|
13
|
+
* [Video of running the v9 installer with Webpacker v3](https://youtu.be/M0WUM_XPaII). History, motivations, philosophy, and overview.
|
14
|
+
1. [GORUCO 2017: Front-End Sadness to Happiness: The React on Rails Story by Justin Gordon](https://www.youtube.com/watch?v=SGkTvKRPYrk)
|
15
|
+
2. [egghead.io: Creating a component with React on Rails](https://egghead.io/lessons/react-creating-a-component-with-react-on-rails)
|
16
|
+
3. [egghead.io: Creating a redux component with React on Rails](https://egghead.io/lessons/react-add-redux-state-management-to-a-react-on-rails-project)
|
17
|
+
4. [React On Rails Tutorial Series](https://www.youtube.com/playlist?list=PL5VAKH-U1M6dj84BApfUtvBjvF-0-JfEU)
|
18
|
+
1. [History and Motivation](https://youtu.be/F4oymbUHvoY)
|
19
|
+
2. [Basic Tutorial Walkthrough](https://youtu.be/_bjScw60FBk)
|
20
|
+
3. [Code Walkthrough](https://youtu.be/McQ9UM-_ocQ)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Client-Side Rendering vs. Server-Side Rendering
|
2
|
+
|
3
|
+
In most cases, you should use the `prerender: false` (default behavior) with the provided helper method to render the React component from your Rails views. In some cases, such as when SEO is vital, or many users will not have JavaScript enabled, you can enable server-rendering by passing `prerender: true` to your helper, or you can simply change the default in `config/initializers/react_on_rails`.
|
4
|
+
|
5
|
+
Now the server will interpret your JavaScript. The default is to use [ExecJS](https://github.com/rails/execjs) and pass the resulting HTML to the client. We recommend using [mini_racer](https://github.com/discourse/mini_racer) as ExecJS's runtime.
|
6
|
+
|
7
|
+
If you want to maximize the perfomance of your server rendering, then you want to use React on Rails Pro which uses NodeJS to do the server rendering. See the [docs for React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki).
|
8
|
+
|
9
|
+
If you open the HTML source of any web page using React on Rails, you'll see the 3 parts of React on Rails rendering:
|
10
|
+
|
11
|
+
1. A script tag containing the properties of the React component, such as the registered name and any props. A JavaScript function runs after the page loads, using this data to build and initialize your React components.
|
12
|
+
2. The wrapper div `<div id="HelloWorld-react-component-0">` specifies the div where to place the React rendering. It encloses the server-rendered HTML for the React component.
|
13
|
+
3. Additional JavaScript is placed to console-log any messages, such as server rendering errors. Note: these server side logs can be configured only to be sent to the server logs.
|
14
|
+
|
15
|
+
**Note**:
|
16
|
+
|
17
|
+
- If server rendering is not used (prerender: false), then the major difference is that the HTML rendered for the React component only contains the outer div: `<div id="HelloWorld-react-component-0"/>`. The first specification of the React component is just the same.
|
@@ -0,0 +1,6 @@
|
|
1
|
+
# Deployment
|
2
|
+
|
3
|
+
- React on Rails puts the necessary precompile steps automatically in the rake precompile step. You can, however, disable this by setting certain values to nil in the [config/initializers/react_on_rails.rb](./configuration.md).
|
4
|
+
- `build_production_command`: Set to nil to turn off the precompilation of the js assets.
|
5
|
+
- `config.symlink_non_digested_assets_regex`: Default is nil, turning off the setup of non-js assets. This should be nil except when when using Sprockets rather than Webpacker.
|
6
|
+
- See the [Heroku Deployment](../additional-reading/heroku-deployment.md) doc for specifics regarding Heroku. The information for Heroku may apply to other deployments.
|
@@ -1,7 +1,4 @@
|
|
1
|
-
|
2
|
-
- [Understanding the Organization of the Generated Client Code](#understanding-the-organization-of-the-generated-client-code)
|
3
|
-
- [Redux](#redux)
|
4
|
-
- [Using Images and Fonts](#using-images-and-fonts)
|
1
|
+
# Generator Details
|
5
2
|
|
6
3
|
The `react_on_rails:install` generator combined with the example pull requests of generator runs will get you up and running efficiently. There's a fair bit of setup with integrating Webpack with Rails. Defaults for options are such that the default is for the flag to be off. For example, the default for `-R` is that `redux` is off, and the default of `-b` is that `skip-bootstrap` is off.
|
7
4
|
|
@@ -41,12 +38,12 @@ Then you may run
|
|
41
38
|
|
42
39
|
More Details:
|
43
40
|
|
44
|
-
`https://github.com/shakacode/react_on_rails/blob/master/docs/basics/generator.md`
|
41
|
+
`https://github.com/shakacode/react_on_rails/blob/master/docs/basics/generator-details.md`
|
45
42
|
```
|
46
43
|
|
47
44
|
Another good option is to create a simple test app per the [Tutorial](../tutorial.md).
|
48
45
|
|
49
|
-
|
46
|
+
# Understanding the Organization of the Generated Client Code
|
50
47
|
The generated client code follows our organization scheme. Each unique set of functionality, is given its own folder inside of `client/app/bundles`. This encourages for modularity of *domains*.
|
51
48
|
|
52
49
|
Inside of the generated "HelloWorld" domain you will find the following folders:
|
@@ -57,7 +54,7 @@ Inside of the generated "HelloWorld" domain you will find the following folders:
|
|
57
54
|
|
58
55
|
You may also notice the `app/lib` folder. This is for any code that is common between bundles and therefore needs to be shared (for example, middleware).
|
59
56
|
|
60
|
-
|
57
|
+
## Redux
|
61
58
|
If you have used the `--redux` generator option, you will notice the familiar additional redux folders in addition to the aforementioned folders. The Hello World example has also been modified to use Redux.
|
62
59
|
|
63
60
|
Note the organizational paradigm of "bundles". These are like application domains and are used for grouping your code into webpack bundles, in case you decide to create different bundles for deployment. This is also useful for separating out logical parts of your application. The concept is that each bundle will have it's own Redux store. If you have code that you want to reuse across bundles, including components and reducers, place them under `/client/app/lib`.
|