Last active
June 17, 2018 16:11
-
-
Save searls/972536bd9479d40461b200d4766814c4 to your computer and use it in GitHub Desktop.
override preact-router so we can synchronously change the route & trigger a render
This file contains 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
/* | |
* override preact-router so we can synchronously change the route & trigger a render | |
* reason for doing this: often a UI action triggers an XHR which in turn will determine | |
* where the user needs to go next (it's a flashcard game, so whether they got it right or wrong | |
* will determine whether their session has concluded, whether to draw the next card, and so on) | |
* as a result we have a lot of action logic that wants to in one-fell-swoop programmatically route | |
* the user to a different component and also update the properties passed to the components by | |
* re-rendering (one big top-level render function, all state just passed by props, no stateful components) | |
* | |
* The practical effect of this change versus the built-in router was that it cuts the number of | |
* calls to render in half when a single event triggers both a route & props change. Particularly | |
* in really slow-painting browsers (actually just Chrome, LOL), users would see a flash of un-updated content. | |
* | |
* Below are just relevant snippets from a larger app and not a runnable example | |
*/ | |
// Custom router | |
class RenderWhileYouRouter extends Router { | |
componentWillReceiveProps(nextProps) { | |
if (nextProps.url && nextProps.url !== this.props.url) { | |
route(nextProps.url) | |
} | |
} | |
} | |
// routing function | |
app.route.andRerender = (path, props) => { | |
app.render(_.extend({}, props, {url: path})) | |
} | |
// render function | |
app.render = (props) => { | |
render( | |
h(app.view.main, props), | |
document.body, | |
document.body.lastElementChild | |
) | |
} | |
// top-level view | |
app.view.main = (props) => { | |
return h('div', {id: 'app', class: 'kamesame'}, | |
app.view.nav(props), | |
h(RenderWhileYouRouter, _.extend({id: 'content'}, props), | |
app.view.route('', app.view.home, props), | |
app.view.route('login', app.view.login, props), | |
app.view.route('lessons', app.view.lessons, props), | |
// ……… | |
app.view.route('account', app.view.account, props), | |
h(app.view.notFound, {default: true}) | |
), | |
app.view.footer() | |
) | |
} | |
// Example action: | |
app.study.handleAnswer = (meaning, node, mode) => { | |
const answer = _.trim(node.value) | |
app.ws.request({id: meaning.id, answer, mode}, (res) => { | |
const props = app.prop.merge(res) | |
app.store.save(props) | |
app.route.andRerender(`/app/${mode}/${meaning.id}/result`, props) | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment