Skip to content

Commit

Permalink
Step 4b: use react-transmit to declaratively define data deps
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dimaip committed Dec 21, 2016
1 parent d9ce281 commit 6defeb1
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 37 deletions.
28 changes: 15 additions & 13 deletions Hello.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import React from 'react';
import s from 'Hello.scss';
import Transmit from 'react-transmit';
import fetch from 'isomorphic-fetch';
import s from 'Hello.scss';

const Hello = React.createClass({
getInitialState: function() {
return {
hello: ''
};
},
componentDidMount: function() {
fetch('/static/data.json')
.then(r => r.json())
.then(r => this.setState({hello: r.hello}));
},
render: function() {
return <div className={s.root}>Hello {this.props.name}. Async hello {this.state.hello}</div>;
return <div className={s.root}>Hello {this.props.name}. Async hello {this.props.hello}</div>;
}
});

export default Hello;
export default Transmit.createContainer(Hello, {
// These must be set, or else it would fail to render
initialVariables: {},
// each fragmen will be resolved into a prop
fragments: {
hello () {
return fetch('http://localhost:3000/static/data.json')
.then(r => r.json())
.then(r => r.hello);
}
}
});
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ Follow the tutorial commit-by-commit, to see the server-side rendering drama unf

## Contents (mostly for Google)

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

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

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

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

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

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

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

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

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

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

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

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


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

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


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

There are multiple ways to solve async rendering issue. Here we'll
use react-transmit to declaratively define our data dependencies per component,
Expand Down
7 changes: 4 additions & 3 deletions client.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Transmit from 'react-transmit';
import Hello from 'Hello';

ReactDOM.render(
<Hello name="World" />,
Transmit.render(
Hello,
{name: 'World'},
document.getElementById('app')
);
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,5 @@
</head>
<body>
<div id="app"></div>
<script src="/built/client.js"></script>
</body>
</html>
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"isomorphic-fetch": "^2.2.1",
"path": "^0.12.7",
"react": "^0.14.8",
"react-dom": "^0.14.8"
"react-dom": "^0.14.8",
"react-transmit": "^3.1.7"
},
"devDependencies": {
"babel-cli": "^6.6.5",
Expand Down
25 changes: 14 additions & 11 deletions serverEntry.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import fs from 'fs';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import Transmit from 'react-transmit';
import Hello from './Hello.js';

function handleRender(req, res) {
const html = ReactDOMServer.renderToString(
<Hello name="World" />
);
fs.readFile('./index.html', 'utf8', function (err, file) {
if (err) {
return console.log(err);
}
const document = file.replace(/<div id="app"><\/div>/, `<div id="app">${html}</div>`);
res.send(document);
});
Transmit.renderToString(Hello, {name: 'World'})
.then(({reactString, reactData}) => {
fs.readFile('./index.html', 'utf8', function (err, file) {
if (err) {
return console.log(err);
}
const document = file.replace(/<div id="app"><\/div>/, `<div id="app">${reactString}</div>`);
const output = Transmit.injectIntoMarkup(document, reactData, ['/built/client.js']);
res.send(output);
});

})
.catch(e => console.log(e));
}

export default handleRender;
2 changes: 1 addition & 1 deletion static/data.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"hello": "world!"
"hello": "WORLD!"
}

0 comments on commit 6defeb1

Please sign in to comment.