Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
EloB committed Mar 7, 2016
0 parents commit f18dbbc
Show file tree
Hide file tree
Showing 16 changed files with 308 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"presets": ["react", "es2015"],
"env": {
"development": {
"presets": ["react-hmre"]
}
}
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
build/
.DS_Store
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Higher order component for fetching data

Here is an example of an higher order component that will take care of fetching data.
It will show an spinner while fetching the data and will show an error if fetching fails to load.
20 changes: 20 additions & 0 deletions application/components/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { Component } from 'react';
import { Link } from 'react-router';

export default class PageRoute extends Component {
render() {
return (
<div>
<ul>
<li>
<Link to="/">Startpage</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
{this.props.children}
</div>
);
}
}
82 changes: 82 additions & 0 deletions application/components/higher-order/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React, { Component } from 'react';
import cancelable from '../../utils/cancelable';

function noop() {}

export default (load = noop) => ComposedComponent => class extends Component {
constructor(...args) {
super(...args);
this.state = {
status: 'idle',
error: null,
};
}

componentWillMount() {
this._preload(this.props, this.state);
}

componentWillUnmount() {
if (this.subscribeLoad) {
this.subscribeLoad.cancel();
}
}

componentWillReceiveProps(nextProps, nextState) {
this._preload(nextProps, nextState);
}

_preload(nextProps, nextState) {
if (this.subscribeLoad) {
this.subscribeLoad.cancel();
}

this.setState({
status: 'loading',
error: null,
});

this.subscribeLoad = cancelable(Promise.all([load(nextProps, nextState)]));

this.subscribeLoad.promise
.then(() => this.setState({ status: 'loaded', error: null }))
.catch(error => {
if (!error.isCancelled) {
this.setState({ status: 'failed', error });
}
});
}

render() {
if (this.state.status === 'failed') {
if (this.state.error instanceof Error) {
return (
<div>
<h1>Error loading page</h1>
{process.env.NODE_ENV === 'development' && this.state.error &&
<pre>{this.state.error.toString()}</pre>
}
</div>
);
}

if (typeof this.state.error === 'string') {
return <h1>{this.state.error}</h1>;
}

return (
<div>
{this.state.error}
</div>
);
}

if (this.state.status === 'loading') {
return <div>Spinner</div>;
}

return (
<ComposedComponent {...this.props} />
);
}
};
4 changes: 4 additions & 0 deletions application/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { render } from 'react-dom';
import routes from './routes';

render(routes, document.getElementById('app'));
28 changes: 28 additions & 0 deletions application/pages/about.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, { Component } from 'react';
import page from '../components/higher-order/page';

class About extends Component {
render() {
return (
<div>About</div>
);
}
}

export default page(
() => new Promise((resolve, reject) => {
const timeout = ~~(Math.random() * 1000);

if (Math.random() > 0.75) {
throw new Error('Random simulated error');
} else if (Math.random() > 0.75) {
setTimeout(reject.bind(null, 'Access denied'), timeout);
} else if (Math.random() > 0.75) {
setTimeout(reject.bind(null, (
<div style={{ color: 'red' }}>Custom error html</div>
)), timeout);
} else {
setTimeout(resolve, timeout);
}
})
)(About);
15 changes: 15 additions & 0 deletions application/pages/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { Component } from 'react';
import page from '../components/higher-order/page';

class Index extends Component {
render() {
return (
<div>
<h1>Home</h1>
<p>Click about link multiple times to see hoc in action</p>
</div>
);
}
}

export default Index;
2 changes: 2 additions & 0 deletions application/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Home } from './home';
export { default as About } from './about';
13 changes: 13 additions & 0 deletions application/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { Router, Route, hashHistory } from 'react-router';
import App from './components/App';
import * as Pages from './pages';

export default (
<Router history={hashHistory}>
<Route component={App}>
<Route path="/" component={Pages.Home} />
<Route path="/about" component={Pages.About} />
</Route>
</Router>
);
11 changes: 11 additions & 0 deletions application/utils/cancelable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default _promise => {
let cancel;
const promise = new Promise((resolve, reject) => {
cancel = () => reject({ isCancelled: true });
return _promise.then(resolve, reject);
});
return {
promise,
cancel,
};
};
9 changes: 9 additions & 0 deletions development/index.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
doctype html
html
head
meta(charset='utf-8')
title Page route example
body
#app
if app && app.js
script(src=app.js.replace('/dist', 'dist'))
9 changes: 9 additions & 0 deletions development/reload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = function reload(assets) {
try {
delete require.cache[require.resolve('../build/webpack-assets')];
} catch (e) {
// Skip
}

return JSON.stringify(assets);
};
30 changes: 30 additions & 0 deletions development/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
var path = require('path');
var express = require('express');
var webpack = require('webpack');
var webpackDevMiddleware = require('webpack-dev-middleware');
var webpackHotMiddleware = require('webpack-hot-middleware');
var config = require('../webpack.config');

module.exports = exports = express();

exports.set('view engine', 'jade');
exports.set('views', __dirname);

var compiler = webpack(config);

exports.use(webpackDevMiddleware(compiler, {
noInfo: true,
publicPath: config.output.publicPath,
}));

exports.use(webpackHotMiddleware(compiler));

exports.get('*', (req, res) => {
var assets = require('../build/webpack-assets');
res.render('index', assets);
});

if (module === require.main) {
var port = process.env.PORT || 3000;
exports.listen(port, e => console[e ? 'error' : 'log'](e || 'Started webserver'));
}
25 changes: 25 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"private": true,
"scripts": {
"start": "NODE_ENV=development ./node_modules/.bin/nodemon -w ./development ./development/server.js",
"build": "NODE_ENV=production ./node_modules/.bin/webpack -p && ./node_modules/.bin/jade -O ./build/webpack-assets.json -o ./build/release ./development/index.jade",
"deploy": "npm run build && git checkout gh-pages && rm -r index.html dist && cp -r build/release/{index.html,dist} . && git add index.html dist && git commit --amend --no-edit && git push --force && git checkout master"
},
"devDependencies": {
"assets-webpack-plugin": "^3.3.0",
"babel-core": "^6.6.5",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babel-preset-react-hmre": "^1.1.1",
"express": "^4.13.4",
"jade": "^1.11.0",
"nodemon": "^1.9.1",
"react": "^0.14.7",
"react-dom": "^0.14.7",
"react-router": "^2.0.0",
"webpack": "^1.12.14",
"webpack-dev-middleware": "^1.5.1",
"webpack-hot-middleware": "^2.9.1"
}
}
45 changes: 45 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
var path = require('path');
var webpack = require('webpack');
var AssetsPlugin = require('assets-webpack-plugin');
var reload = require('./development/reload');

module.exports = {
devtool: 'cheap-eval-module-source-map',
entry: {
app: [].concat(
process.env.NODE_ENV === 'development' ? [
'webpack-hot-middleware/client',
] : [],
path.join(__dirname, 'application/index')
),
},
output: {
path: path.join(__dirname, 'build/release/dist'),
filename: '[name].[hash].js',
publicPath: process.env.NODE_ENV === 'production' ? 'dist/' : '/dist/',
},
module: {
loaders: [
{ test: /\.jsx?$/, include: path.join(__dirname, 'application'), loader: 'babel' },
],
},
plugins: [].concat(
process.env.NODE_ENV === 'development' ? [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
] : [],
[
new webpack.DefinePlugin({
process: {
env: {
NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'production'),
},
},
}),
new AssetsPlugin({
path: path.join(__dirname, 'build'),
processOutput: reload,
}),
]
),
};

0 comments on commit f18dbbc

Please sign in to comment.