Last active
March 25, 2016 13:59
-
-
Save frenzzy/7b753d09110389731a3e to your computer and use it in GitHub Desktop.
React Starter Kit Hot Router
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
/** | |
* React Starter Kit (https://www.reactstarterkit.com/) | |
* | |
* Copyright © 2014-2016 Kriasoft, LLC. All rights reserved. | |
* | |
* This source code is licensed under the MIT license found in the | |
* LICENSE.txt file in the root directory of this source tree. | |
*/ | |
import 'babel-polyfill'; | |
import ReactDOM from 'react-dom'; | |
import FastClick from 'fastclick'; | |
import Router from './routes'; | |
import Location from './core/Location'; | |
import { addEventListener, removeEventListener } from './core/DOMUtils'; | |
let cssContainer = document.getElementById('css'); | |
const appContainer = document.getElementById('app'); | |
const context = { | |
insertCss: styles => styles._insertCss(), | |
onSetTitle: value => (document.title = value), | |
onSetMeta: (name, content) => { | |
// Remove and create a new <meta /> tag in order to make it work | |
// with bookmarks in Safari | |
const elements = document.getElementsByTagName('meta'); | |
Array.from(elements).forEach((element) => { | |
if (element.getAttribute('name') === name) { | |
element.parentNode.removeChild(element); | |
} | |
}); | |
const meta = document.createElement('meta'); | |
meta.setAttribute('name', name); | |
meta.setAttribute('content', content); | |
document | |
.getElementsByTagName('head')[0] | |
.appendChild(meta); | |
}, | |
}; | |
// Google Analytics tracking. Don't send 'pageview' event after the first | |
// rendering, as it was already sent by the Html component. | |
let trackPageview = () => (trackPageview = () => window.ga('send', 'pageview')); | |
let HotRouter = Router; | |
function render(state) { | |
HotRouter.dispatch(state, (newState, component) => { | |
ReactDOM.render(component, appContainer, () => { | |
// Restore the scroll position if it was saved into the state | |
if (state.scrollY !== undefined) { | |
window.scrollTo(state.scrollX, state.scrollY); | |
} else { | |
window.scrollTo(0, 0); | |
} | |
trackPageview(); | |
// Remove the pre-rendered CSS because it's no longer used | |
// after the React app is launched | |
if (cssContainer) { | |
cssContainer.parentNode.removeChild(cssContainer); | |
cssContainer = null; | |
} | |
}); | |
}); | |
} | |
function run() { | |
let currentLocation = null; | |
let currentState = null; | |
// Make taps on links and buttons work fast on mobiles | |
FastClick.attach(document.body); | |
// Re-render the app when window.location changes | |
const unlisten = Location.listen(location => { | |
currentLocation = location; | |
currentState = Object.assign({}, location.state, { | |
path: location.pathname, | |
query: location.query, | |
state: location.state, | |
context, | |
}); | |
render(currentState); | |
}); | |
// Save the page scroll position into the current location's state | |
const supportPageOffset = window.pageXOffset !== undefined; | |
const isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat'); | |
const setPageOffset = () => { | |
currentLocation.state = currentLocation.state || Object.create(null); | |
if (supportPageOffset) { | |
currentLocation.state.scrollX = window.pageXOffset; | |
currentLocation.state.scrollY = window.pageYOffset; | |
} else { | |
currentLocation.state.scrollX = isCSS1Compat ? | |
document.documentElement.scrollLeft : document.body.scrollLeft; | |
currentLocation.state.scrollY = isCSS1Compat ? | |
document.documentElement.scrollTop : document.body.scrollTop; | |
} | |
}; | |
addEventListener(window, 'scroll', setPageOffset); | |
addEventListener(window, 'pagehide', () => { | |
removeEventListener(window, 'scroll', setPageOffset); | |
unlisten(); | |
}); | |
if (module.hot) { | |
module.hot.accept('./routes', () => { | |
HotRouter = require('./routes').default; | |
render(currentState); | |
}); | |
} | |
} | |
// Run the application when both DOM is ready and page content is loaded | |
if (['complete', 'loaded', 'interactive'].includes(document.readyState) && document.body) { | |
run(); | |
} else { | |
document.addEventListener('DOMContentLoaded', run, false); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment