Permalink
Browse files

Client App

  • Loading branch information...
alexishevia committed Nov 27, 2014
1 parent 1e08f68 commit b7b6f4b17cd3c4165cfc4a313860d97a412b7078
Showing with 85 additions and 6 deletions.
  1. +9 −0 README.md
  2. +17 −0 client.js
  3. +10 −2 components/Application.jsx
  4. +2 −0 components/HTML.jsx
  5. +5 −0 npm-shrinkwrap.json
  6. +5 −2 package.json
  7. +10 −2 server.js
  8. +9 −0 stores/ApplicationStore.js
  9. +18 −0 webpack.config.js
View
@@ -35,3 +35,12 @@ Note: We're using the FluxibleMixin, which includes a handy `getStore()` method
// To get styling
- Create an `<HTML>` component, to render the base template for our app (including styles)
- Modify server.js so it renders the app component inside the html component
## Client App
- Add dehydrate and rehydrate functions to our ApplicationStore, to control how its serialized/deserialized.
- Use express-state to expose current state to `res.local.state`, inside an `App` namespace. Current state is obtained by calling app.dehydrate(), which in turn calls dehydrate() on all stores registered with the app.
- Modify the `<HTML>` component so it renders res.local.state.
- Create client.js. It will create a new app instance, and rehydrate it with the state passed from the server.
- Use webpack to compile/bundle the client. Modify `<HTML>` so it loads the bundled client.
- Add a store listener on `<Application>` so it updates whenever the ApplicationStore changes (eg: when the user clicks on a link and the current route changes)
- Add the RouterMixin to `<Application>` so the browser URL is updated correctly when the user visits a new route.
View
@@ -0,0 +1,17 @@
'use strict';
var React = require('react');
var app = require('./app');
var dehydratedState = window.App; // Sent from the server
window.React = React; // For chrome dev tool support
app.rehydrate(dehydratedState, function (err, context) {
if (err) {
throw err;
}
var mountNode = document.getElementById('app');
React.render(app.getAppComponent()({
context: context.getComponentContext()
}), mountNode);
});
View
@@ -1,16 +1,24 @@
'use strict';
var React = require('react');
var ApplicationStore = require('../stores/ApplicationStore');
var Home = require('./Home.jsx');
var About = require('./About.jsx');
var Nav = require('./Nav.jsx');
var ApplicationStore = require('../stores/ApplicationStore');
var RouterMixin = require('flux-router-component').RouterMixin;
var FluxibleMixin = require('fluxible').Mixin;
var Application = React.createClass({
mixins: [FluxibleMixin],
mixins: [RouterMixin, FluxibleMixin],
statics: {
storeListeners: [ApplicationStore]
},
getInitialState: function () {
return this.getStore(ApplicationStore).getState();
},
onChange: function () {
var state = this.getStore(ApplicationStore).getState();
this.setState(state);
},
render: function(){
return (
<div>
View
@@ -14,6 +14,8 @@ module.exports = React.createClass({
<body>
<div id="app" dangerouslySetInnerHTML={{__html: this.props.markup}}></div>
</body>
<script dangerouslySetInnerHTML={{__html: this.props.state}}></script>
<script src="/public/js/client.js" defer></script>
</html>
);
}
View

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
View
@@ -3,17 +3,20 @@
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "./node_modules/.bin/nodemon -e js,jsx server.js"
"dev": "./node_modules/.bin/nodemon --ignore build/ -e js,jsx server.js & ./node_modules/.bin/webpack --watch"
},
"dependencies": {
"express": "4.11.2",
"express-state": "1.2.0",
"node-jsx": "0.12.4",
"react": "0.12.2",
"flux-router-component": "0.4.6",
"fluxible": "0.2.0",
"fluxible-plugin-routr": "0.2.1"
},
"devDependencies": {
"nodemon": "1.3.6"
"nodemon": "1.3.6",
"webpack": "1.5.3",
"jsx-loader": "0.12.2"
}
}
View
@@ -1,13 +1,17 @@
'use strict';
require('node-jsx').install({ extension: '.jsx' });
var express = require('express');
var server = express();
var port = process.env.PORT || 3000;
var navigateAction = require('flux-router-component').navigateAction;
var React = require('react');
var app = require('./app');
var HtmlComponent = React.createFactory(require('./components/HTML.jsx'));
var server = express();
server.use('/public', express.static(__dirname + '/build'));
var expressState = require('express-state');
expressState.extend(server);
server.use(function(req, res, next) {
var context = app.createContext();
@@ -23,8 +27,11 @@ server.use(function(req, res, next) {
return;
}
res.expose(app.dehydrate(context), 'App');
var AppComponent = app.getAppComponent();
var html = React.renderToStaticMarkup(HtmlComponent({
state: res.locals.state,
markup: React.renderToString(AppComponent({
context: context.getComponentContext()
}))
@@ -34,5 +41,6 @@ server.use(function(req, res, next) {
});
});
var port = process.env.PORT || 3000;
server.listen(port);
console.log('Listening on port ' + port);
@@ -39,6 +39,15 @@ var ApplicationStore = createStore({
pages: this.pages,
route: this.currentRoute
};
},
dehydrate: function () {
return this.getState();
},
rehydrate: function (state) {
this.currentPageName = state.currentPageName;
this.currentPage = state.currentPage;
this.pages = state.pages;
this.currentRoute = state.route;
}
});
View
@@ -0,0 +1,18 @@
'use strict';
var webpack = require('webpack');
module.exports = {
resolve: {
extensions: ['', '.js', '.jsx']
},
entry: './client.js',
output: {
path: __dirname+'/build/js',
filename: 'client.js'
},
module: {
loaders: [
{ test: /\.jsx$/, loader: 'jsx-loader' }
]
}
};

0 comments on commit b7b6f4b

Please sign in to comment.