Last active
August 29, 2017 06:16
-
-
Save steve-taylor/100ff147d26b2342854fc04e2208636f to your computer and use it in GitHub Desktop.
Routing to React pages using Page.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>React + Bacon.js + Page.js</title> | |
<script src="https://unpkg.com/[email protected]/babel.min.js"></script> | |
<script src="https://unpkg.com/react@latest/dist/react.js"></script> | |
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/bacon.js/0.7.95/Bacon.min.js"></script> | |
<script src="https://cdn.rawgit.com/visionmedia/page.js/master/page.js"></script> | |
</head> | |
<body> | |
<div id="react-app"></div> | |
<script type="text/babel" data-presets="es2015,stage-2,react"> | |
const startRoutingBus = new Bacon.Bus(); | |
const loginBus = new Bacon.Bus(); | |
const logoutBus = new Bacon.Bus(); | |
const LandingPage = () => ( | |
<div> | |
Loading... | |
</div> | |
); | |
const HomePage = () => ( | |
<div> | |
Home | |
</div> | |
); | |
const UserPage = ({username, givenName, familyName, onLogout}) => ( | |
<div> | |
<table> | |
<thead> | |
<tr> | |
<th>Name</th> | |
<th>Value</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr> | |
<td>Username</td> | |
<td>{username}</td> | |
</tr> | |
<tr> | |
<td>Given name</td> | |
<td>{givenName}</td> | |
</tr> | |
<tr> | |
<td>Family name</td> | |
<td>{familyName}</td> | |
</tr> | |
</tbody> | |
</table> | |
<div> | |
<button onClick={onLogout}> | |
Log out | |
</button> | |
</div> | |
</div> | |
); | |
const LoginPage = ({onLogin}) => ( | |
<div> | |
<h2>Login</h2> | |
<div> | |
<button | |
onClick={() => { | |
setTimeout(() => onLogin({ | |
username: 'another.user', | |
givenName: 'Another', | |
familyName: 'User' | |
}), 1000); | |
}} | |
> | |
Log in | |
</button> | |
</div> | |
</div> | |
); | |
const NotFoundPage = () => ( | |
<div> | |
Not found | |
</div> | |
); | |
const userProp = Bacon.update( | |
null, | |
[loginBus], (state, {username, givenName, familyName}) => ({ | |
username, | |
givenName, | |
familyName | |
}), | |
[logoutBus], () => null | |
); | |
loginBus.onValue(() => { | |
page('/user'); | |
}); | |
logoutBus.onValue(() => { | |
page('/login'); | |
}); | |
const appState = Bacon.combineTemplate({ | |
user: userProp | |
// and so on... | |
}); | |
const mountPoint = document.getElementById('react-app'); | |
// Show landing page, wait for startRoutingBus, and start routing and combining the route stream with appState. | |
// (Probably could be broken up a bit, although this way, you can see how it all flows.) | |
Bacon | |
.later(0, <LandingPage/>) | |
.concat( | |
startRoutingBus.flatMapLatest( | |
() => appState.combine( | |
// Generate a stream from page.js mappings to page-level components. | |
Bacon.fromBinder( | |
sink => { | |
page('/', () => { | |
sink(() => ( | |
<HomePage/> | |
)); | |
}); | |
page('/login', () => { | |
sink(() => ( | |
<LoginPage | |
onLogin={({username, givenName, familyName}) => { | |
loginBus.push({username, givenName, familyName}); | |
}} | |
/> | |
)); | |
}); | |
page('/user', () => { | |
sink(({user}) => ( | |
<UserPage | |
{...user} | |
onLogout={() => { | |
logoutBus.push(); | |
}} | |
/> | |
)); | |
}); | |
page('*', () => { | |
sink(() => ( | |
<NotFoundPage/> | |
)); | |
}); | |
page(); | |
return () => { | |
page.stop(); | |
}; | |
} | |
), | |
(app, Page) => ( | |
<Page {...app}/> | |
) | |
) | |
) | |
) | |
.onValue(page => { | |
ReactDOM.render(page, mountPoint); | |
}); | |
setTimeout(() => { | |
// Start mapping routes to the page stream. (Needs to start before pushing any app state.) | |
startRoutingBus.push(); | |
// Push user info to the appState.user property. | |
loginBus.push({ | |
username: 'john.smith', | |
givenName: 'John', | |
familyName: 'Smith' | |
}); | |
}, 1000); // 1s delay to simulate loading current user from an endpoint | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment