Skip to content

Instantly share code, notes, and snippets.

@seanhess
Created December 18, 2014 16:36
Show Gist options
  • Save seanhess/b8ada5fe0e1ae85be5ff to your computer and use it in GitHub Desktop.
Save seanhess/b8ada5fe0e1ae85be5ff to your computer and use it in GitHub Desktop.
Omniscient React Router
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Omniscient</title>
</head>
<body>
<div id="content"></div>
<script src="bundle.js"></script>
</body>
</html>
var React = require('react')
var immstruct = require('immstruct')
var Immutable = require('immutable')
var component = require('omniscient')
var Router = require('react-router')
var axios = require('axios')
var {Route, DefaultRoute, Link, RouteHandler} = Router
// KNOWN ISSUES:
// I have to use React components as page handlers to be able to grab a cursor from the state. I don't want to pass the same cursor to every single page. They might use very different data, or get it from different immstruct objects
// I have to use React components as page handlers to get access to the lifecycle methods (not React-Router's fault, really, but I can get it much cleaner with page.js. It would be nice if there was some way to give Router a function to call when the url was hit, which returned a render function or another component that could be called to render
// Loading ajax: componentWillReceiveProps gets called over and over again as the request finishes and updates the state. Is there a correct way to do this?
// STATE ----------------------------------------------------
var state = immstruct({
greeting: {message:'Hello there!'},
info: {},
})
// WELCOME PAGE --------------------------------------------
var WelcomePage = React.createClass({
// I want to select a particular cursor for this component
// note that it might even be from another immstruct!
render: function() {
return <Welcome greeting={state.cursor('greeting')} />
},
})
var Welcome = component(function({greeting}) {
function onChange(e) {
greeting.update('message', () => e.target.value)
}
return <div>
<div>{greeting.get('message')}</div>
<div><input type="text" value={greeting.get('message')} onChange={onChange}/></div>
</div>
}).jsx
// INFO PAGE ---------------------------------------------
var InfoPage = React.createClass({
mixins: [Router.State],
// I want to load some ajax data when this page is loaded
// is this the correct pattern for react router?
load: function() {
loadInfo(this.getParams().id)
.then(function(info) {
state.cursor('info').update(() => Immutable.fromJS(info))
})
},
componentWillMount: function() {
this.load()
},
// this gets called over and over again, once the request finishes it updates the state
// which causes this to get called again
componentWillReceiveProps: function() {
this.load()
},
render: function() {
return <Info info={state.cursor('info')}/>
},
})
// This is my real component
var Info = component(function({info}) {
return <div>Current Time is: {info.get('test')}</div>
}).jsx
// ROOT COMPONENT -------------------------------------------o
// The Root Component. When I tried changing this to omniscient, RouteHandler didn't change
var App = React.createClass({
render: function () {
return (
<div>
<header>
<ul>
<li><Link to="app">WElcome</Link></li>
<li><a href="#info/woot">Info Woot</a></li>
<li><a href="#info/boot">Info Boot</a></li>
</ul>
</header>
<RouteHandler/>
</div>
);
}
});
// ROUTES ------------------------------------------------
var routes = (
<Route name="app" path="/" handler={App}>
<Route name="info" path="/info/:id" handler={InfoPage}/>
<DefaultRoute handler={WelcomePage}/>
</Route>
);
var Handler;
Router.run(routes, function (h) {
Handler = h
render()
});
function render () {
if (!Handler) return
React.render(<Handler/>, document.querySelector("#content"));
}
render()
state.on('swap', render);
// AJAX -----------------------------------------------------
// Example AJAX call, just returns {test:<id>}
function loadInfo(id) {
return axios.get('http://echo.jsontest.com/test/' + id)
.then((rs) => rs.data)
}
{
"name": "react-omniscient",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"axios": "0.4.2",
"immstruct": "1.2.1",
"immutable": "3.4.0",
"omniscient": "2.0.1",
"react": "0.12.1",
"react-router": "0.11.6"
},
"devDependencies": {
"jsx-loader": "0.12.2",
"webpack": "1.4.13"
}
}
module.exports = {
entry: './index.jsx',
output: {
path: './',
filename: 'bundle.js'
},
resolve: {
extensions: ['', '.js', '.json', '.jsx', 'index.jsx', 'index.js', '.styl']
},
module: {
loaders: [
{ test: /\.jsx?$/, loader: 'jsx-loader?harmony'},
]
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment