Skip to content

Commit 6defeb1

Browse files
committed
Step 4b: use react-transmit to declaratively define data deps
There are multiple ways to solve async rendering issue. Here we'll use react-transmit to declaratively define our data dependencies per component, and return rendered html only when all data is resolved. It works even with nested components, constructing the single promises tree, which is qute cool. It is inspired by Facebook Relay, so if you are familiar with it, you'll feel right at home.
1 parent d9ce281 commit 6defeb1

File tree

7 files changed

+43
-37
lines changed

7 files changed

+43
-37
lines changed

Hello.js

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import React from 'react';
2-
import s from 'Hello.scss';
2+
import Transmit from 'react-transmit';
33
import fetch from 'isomorphic-fetch';
4+
import s from 'Hello.scss';
45

56
const Hello = React.createClass({
6-
getInitialState: function() {
7-
return {
8-
hello: ''
9-
};
10-
},
11-
componentDidMount: function() {
12-
fetch('/static/data.json')
13-
.then(r => r.json())
14-
.then(r => this.setState({hello: r.hello}));
15-
},
167
render: function() {
17-
return <div className={s.root}>Hello {this.props.name}. Async hello {this.state.hello}</div>;
8+
return <div className={s.root}>Hello {this.props.name}. Async hello {this.props.hello}</div>;
189
}
1910
});
2011

21-
export default Hello;
12+
export default Transmit.createContainer(Hello, {
13+
// These must be set, or else it would fail to render
14+
initialVariables: {},
15+
// each fragmen will be resolved into a prop
16+
fragments: {
17+
hello () {
18+
return fetch('http://localhost:3000/static/data.json')
19+
.then(r => r.json())
20+
.then(r => r.hello);
21+
}
22+
}
23+
});

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ Follow the tutorial commit-by-commit, to see the server-side rendering drama unf
77

88
## Contents (mostly for Google)
99

10-
### Step 1: minimal Webpack, Babel and React setup
10+
### [Step 1: minimal Webpack, Babel and React setup](https://github.com/dimaip/server-side-rendering/commit/7d1d0677bca0ea94e820dc7e156c89e83ef823bb)
1111

1212
RUN: `npm run start` and then open index.html in the browser.
1313

1414
Webpack helps us to bundle our code with dependencies from npm
1515
(such as React), and then transforms the code with Babel, to make
1616
it compatible with ES5.
1717

18-
### Step 2: trivial server-side rendering with Express
18+
### [Step 2: trivial server-side rendering with Express](https://github.com/dimaip/server-side-rendering/commit/fad6b64e4ec3ee6b378c6ab0abd36f03fdba7c77)
1919

2020
RUN: `npm run start` and go to `http://localhost:3000`.
2121

@@ -25,7 +25,7 @@ server the client with rendered html, and with webpack we continue to
2525
bundle client.js into ES5 code that the browser would understand,
2626
just as we did at previous step.
2727

28-
### Step 3: Add styles
28+
### [Step 3: add styles](https://github.com/dimaip/server-side-rendering/commit/53d2ffa7bc9319722addced5bb94c5b231726a1b)
2929

3030
Now lets learn to deal with styles. We configure webpack loaders to
3131
support loading CSS files. This is cool, but there comes one problem
@@ -36,7 +36,7 @@ Let's fix this problem with webpack's ExtractTextPlugin plugin: it
3636
extracts all CSS styles into one CSS file that we can serve to our client,
3737
so our page will instantly look perfectly styled, even without JS.
3838

39-
### Step 3a: switch to CSS modules
39+
### [Step 3a: switch to CSS modules](https://github.com/dimaip/server-side-rendering/commit/e2c02444b1e7c6ec349511aa9b2da1a52aba5474)
4040

4141
Everybody loves CSS modules, and the great news is that they come free with Webpack.
4242
The bad news is that we can't use them with server-side rendering, as we don't use
@@ -46,7 +46,7 @@ So at this step we broke everything, and the only way to continue from here, is
4646
start using Webpack to pre-build code for server-side rendering too, and that's
4747
what we'll do at the next step.
4848

49-
### Step 3b: save the day by making webpack to render server-side code
49+
### [Step 3b: save the day by making webpack to render server-side code](https://github.com/dimaip/server-side-rendering/commit/6e36b9690816d414ca36775c6487e0b6dbd8abe3)
5050

5151
To save our issue with CSS modules, we make Webpack to render both
5252
our client and our server side code. The best way to do it is to
@@ -64,7 +64,7 @@ Great! Now our build is fixed, so we can use CSS modules both during client
6464
and server rendering.
6565

6666

67-
### Step 4a: asyncronously fetching data
67+
### [Step 4a: asyncronously fetching data](https://github.com/dimaip/server-side-rendering/commit/d9ce281b88d142cf52861223a201de6d47dfd428)
6868

6969
Now let's fetch some data asyncronously. We'll use isomorphic-fetch,
7070
as it works both on client and server our of the box.
@@ -76,7 +76,7 @@ async data when it arrives.
7676
Let's try to fix it in the next step.
7777

7878

79-
### Step 4b: use react-transmit to declaratively define data deps
79+
### [Step 4b: use react-transmit to declaratively define data deps](https://github.com/dimaip/server-side-rendering/commit/HEAD)
8080

8181
There are multiple ways to solve async rendering issue. Here we'll
8282
use react-transmit to declaratively define our data dependencies per component,

client.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React from 'react';
2-
import ReactDOM from 'react-dom';
2+
import Transmit from 'react-transmit';
33
import Hello from 'Hello';
44

5-
ReactDOM.render(
6-
<Hello name="World" />,
5+
Transmit.render(
6+
Hello,
7+
{name: 'World'},
78
document.getElementById('app')
89
);

index.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,5 @@
66
</head>
77
<body>
88
<div id="app"></div>
9-
<script src="/built/client.js"></script>
109
</body>
1110
</html>

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"isomorphic-fetch": "^2.2.1",
1414
"path": "^0.12.7",
1515
"react": "^0.14.8",
16-
"react-dom": "^0.14.8"
16+
"react-dom": "^0.14.8",
17+
"react-transmit": "^3.1.7"
1718
},
1819
"devDependencies": {
1920
"babel-cli": "^6.6.5",

serverEntry.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
import fs from 'fs';
22
import React from 'react';
3-
import ReactDOMServer from 'react-dom/server';
3+
import Transmit from 'react-transmit';
44
import Hello from './Hello.js';
55

66
function handleRender(req, res) {
7-
const html = ReactDOMServer.renderToString(
8-
<Hello name="World" />
9-
);
10-
fs.readFile('./index.html', 'utf8', function (err, file) {
11-
if (err) {
12-
return console.log(err);
13-
}
14-
const document = file.replace(/<div id="app"><\/div>/, `<div id="app">${html}</div>`);
15-
res.send(document);
16-
});
7+
Transmit.renderToString(Hello, {name: 'World'})
8+
.then(({reactString, reactData}) => {
9+
fs.readFile('./index.html', 'utf8', function (err, file) {
10+
if (err) {
11+
return console.log(err);
12+
}
13+
const document = file.replace(/<div id="app"><\/div>/, `<div id="app">${reactString}</div>`);
14+
const output = Transmit.injectIntoMarkup(document, reactData, ['/built/client.js']);
15+
res.send(output);
16+
});
17+
18+
})
19+
.catch(e => console.log(e));
1720
}
1821

1922
export default handleRender;

static/data.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"hello": "world!"
2+
"hello": "WORLD!"
33
}

0 commit comments

Comments
 (0)