Skip to content

Commit 106bc50

Browse files
committed
Wrote introduction. Removed react-router from basic example.
1 parent d79a044 commit 106bc50

File tree

1 file changed

+21
-57
lines changed

1 file changed

+21
-57
lines changed

docs/recipes/ServerRendering.md

Lines changed: 21 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
# Server Rendering
22

3-
## Redux and Server Side Rendering
4-
Redux is well-suited for server side rendering. This is because Redux does not rely on _singletons_.
3+
The most common use case for server-side rendering is to handle the _initial render_ when a user (or search engine crawler) first requests our app. When the server receives the request, it renders the required component(s) into an HTML string, and then sends it as a response to the client. From that point on, the client takes over rendering duties.
54

6-
Redux's job on the server side is to provide the initial state for the initial render of our app. To get this, we need to create a new instance of a Redux store for every new request.
5+
### Redux on the server
6+
When using a store like Redux, we must also send the initial state of our app along in our response. To do this, we need to: create a fresh, new Redux store instance on every request, optionally dispatch some actions, pull the state out of store, and then pass the state along to the client. On the client side, a new Redux store will be created and initialized with the state provided from the server.
77

8-
In the following recipe, we are going to look at how to set up server side rendering. We are going to use the code from our Todo List app that we built in Basics as a guide, but shouldn't need to touch any of the actions, reducers, or components from that tutorial.
8+
Redux's **_only_** job on the server side is to provide the **initial state** of our app.
9+
10+
-----
11+
12+
In the following recipe, we are going to look at how to set up server-side rendering, using the [Todo List app](../basics/ExampleTodoList.html) that we built in [Basics](../basics/) as a guide.
913

1014
## Setting Up
1115

1216
### File Structure
13-
We are going to move our actions, reducers, routes, and components from our Todo List app into a `shared/` folder, since they will be used by both the client and server. Note that we have moved our client-side entrypoint into the `client/` folder.
17+
We are going to put the actions, reducers, and components from the Todo List app into a `shared/` folder, since they will be used by both the client and server. Note that we have moved our client-side entrypoint into the `client/` folder.
1418

1519
server.jsx
1620
client/index.jsx
1721
shared/actions.js
1822
shared/reducers.js
19-
shared/routes.js
2023
shared/containers/App.js
2124
shared/components/AddTodo.js
2225
shared/components/Footer.js
@@ -25,45 +28,26 @@ We are going to move our actions, reducers, routes, and components from our Todo
2528

2629

2730
### Install Packages
28-
For this example, we will be using [Express](http://expressjs.com/) as a simple web server.
29-
30-
We are going to be using [React Router v. 1.0.0-beta3](https://rackt.github.io/react-router/) to handle both our back-end and front-end routes.
31+
For this example, we'll be using [Express](http://expressjs.com/) as a simple web server.
3132

3233
We also need to install the React bindings for Redux, since they are not included in Redux by default.
3334

3435

35-
npm install --save react redux express [email protected] react-redux
36+
npm install --save express react-redux
3637

3738

3839
## The Server Side
3940

40-
**shared/routes.js**
41-
42-
These routes are used for **both** the client and server side. These are used by React Router to fetch the proper component for a specific route.
43-
```js
44-
import React from 'react';
45-
import { DefaultRoute, Route } from 'react-router';
46-
import App from 'containers/App';
47-
import Footer from 'components/Footer';
48-
49-
export default (
50-
<Route path="/" component={App}/>
51-
);
52-
53-
```
54-
5541
**server.jsx**
5642

5743
The following is the outline for what our server side is going to look like. We are going to set up an [Express middleware](http://expressjs.com/guide/using-middleware.html) using [app.use](http://expressjs.com/api.html#app.use) to handle all requests that come in to our server. If you're unfamiliar with Express or middleware, just know that our handleRender function will be called every time the server receives a request.
5844
```js
5945
import Express from 'express';
6046
import React from 'react';
61-
import { Router } from 'react-router';
62-
import Location from 'react-router/lib/Location';
6347
import { createStore } from 'redux';
6448
import { Provider } from 'react-redux';
65-
import routes from './shared/routes';
6649
import todoApp from './shared/reducers';
50+
import App from './shared/containers/App';
6751

6852
var app = Express();
6953

@@ -72,46 +56,30 @@ app.use(handleRender);
7256

7357
// We are going to fill these out in the sections to follow
7458
function handleRender(req, res) { // ... }
75-
function renderRoute(err, routeState) { //... }
7659
function renderFullPage(html, initialState) { //... }
7760

7861
export default app;
7962
```
8063
8164
**Handling The Request**
8265
83-
Every time a request is received, the first thing we need to do is create a new Redux store instance. The only purpose of this store instance is to provide the initial state of our application. Next, we pass our routes and the requested location to React Router. React Router is going to look at our **routes.js** and fetch the component that should handle the requested route.
84-
```js
85-
function handleRender(req, res) {
86-
// Create a new Redux store instance
87-
var store = createStore(todoApp);
88-
89-
// Create a new Location based on the requested path
90-
var location = new Location(req.path, req.query);
66+
The first thing that we need to do on every request is create a new Redux store instance. The only purpose of this store instance is to provide the initial state of our application.
9167
92-
// Run React Router with the given location and our routes
93-
// renderRoute is the callback that will be fired
94-
Router.run(routes, location, renderRoute);
95-
};
96-
```
97-
98-
**Rendering the Component**
68+
When rendering, we will wrap `<App/>`, our root component, inside a `<Provider>` to make the store available to all components in the component tree.
9969
10070
The key step in server side rendering is to render the initial HTML of our component _**before**_ we send it to the client side. To do this, we use [React.renderToString](https://facebook.github.io/react/docs/top-level-api.html#react.rendertostring).
10171
102-
We wrap our root component in Provider to make the store available to all components in the component tree.
72+
We then get the initial state from our Redux store using **store.getState()**. We will see how this is passed along in our `renderFullPage` function.
10373
104-
We also need to get the initial state from our Redux store, so that we can pass it along to the client as well. We get the initial state using **store.getState()**. We will see how this is passed along in our _renderFullPage_ function.
10574
```js
106-
function renderRoute(err, routeState) {
107-
if(err) return console.error(err);
75+
function handleRender(req, res) {
76+
// Create a new Redux store instance
77+
var store = createStore(todoApp);
10878

10979
// Render the component to a string
11080
var html = React.renderToString(
11181
<Provider store={store}>
112-
{() =>
113-
<Router {...routeState} />
114-
}
82+
{ () => <App/> }
11583
</Provider>);
11684

11785
// Grab the initial state from our Redux store
@@ -148,21 +116,17 @@ function renderFullPage(html, initialState) {
148116
149117
## The Client Side
150118
151-
The client side is very straightforward. All we need to do is _hydrate_ our store by grabbing `window.__INITIAL_STATE__` and passing it to our createStore function as the initial state.
152-
153-
We also need to pass the Router in as our child to Provider, rather than our App component.
119+
The client side is very straightforward. All we need to do is grab the initial state from `window.__INITIAL_STATE__`, and pass it to our createStore function as the initial state.
154120
155121
Let's take a look at our new `client/index.jsx`:
156122
157123
**client/index.jsx**
158124
```js
159125
import React from 'react';
160-
import { Router } from 'react-router';
161126
import { createStore } from 'redux';
162127
import { Provider } from 'react-redux';
163128
import App from '../shared/containers/App';
164129
import todoApp from '../shared/reducers';
165-
import routes from '../shared/routes';
166130

167131
const initialState = window.__INITIAL_STATE__;
168132

@@ -173,7 +137,7 @@ React.render(
173137
// The child must be wrapped in a function
174138
// to work around an issue in React 0.13.
175139
<Provider store={store}>
176-
{() => <Router children={routes} />}
140+
{() => <App/>}
177141
</Provider>,
178142
rootElement
179143
);

0 commit comments

Comments
 (0)