Last active
December 2, 2017 21:19
-
-
Save tomatau/9c6011dcb5b9f357368aac2b3a2b1430 to your computer and use it in GitHub Desktop.
SSR React Router Redux Suggestion
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
import { Switch, Route } from 'react-router' | |
import { replace } from 'react-router-redux' | |
@connect(null, { replace }) | |
class PrivateRoute extends React.Component { | |
componentWillMount() { | |
this.props.replace('/foo') | |
} | |
render() { | |
return ( | |
<h1>Private</h1> | |
) | |
} | |
} | |
export default class App extends React.Component { | |
render() { | |
return ( | |
<div> | |
<Switch> | |
<Route path='/private' component={PrivateRoute} /> | |
</Switch> | |
</div> | |
) | |
} | |
} |
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
import invariant from 'invariant' | |
import { addLeadingSlash, createPath, parsePath } from 'history/PathUtils' | |
const noop = () => {} | |
const normalizeLocation = (object) => { | |
const { pathname = '/', search = '', hash = '' } = object | |
return { | |
pathname, | |
search: search === '?' ? '' : search, | |
hash: hash === '#' ? '' : hash, | |
} | |
} | |
const addBasename = (basename, location) => { | |
if (!basename) | |
return location | |
return { | |
...location, | |
pathname: addLeadingSlash(basename) + location.pathname, | |
} | |
} | |
const stripBasename = (basename, location) => { | |
if (!basename) | |
return location | |
const base = addLeadingSlash(basename) | |
if (location.pathname.indexOf(base) !== 0) | |
return location | |
return { | |
...location, | |
pathname: location.pathname.substr(base.length), | |
} | |
} | |
const createLocation = (location) => | |
typeof location === 'string' ? parsePath(location) : normalizeLocation(location) | |
const createURL = (location) => | |
typeof location === 'string' ? location : createPath(location) | |
const staticHandler = (methodName) => () => { | |
invariant( | |
false, | |
'You cannot %s with <StaticRouter>', | |
methodName | |
) | |
} | |
const createStaticHistory = (basename='', location='/') => { | |
const createHref = (path) => | |
addLeadingSlash(basename + createURL(path)) | |
const handlePush = (location) => { | |
history.context.action = 'PUSH' | |
history.context.location = addBasename(basename, createLocation(location)) | |
history.context.url = createURL(history.context.location) | |
} | |
const handleReplace = (location) => { | |
history.context.action = 'REPLACE' | |
history.context.location = addBasename(basename, createLocation(location)) | |
history.context.url = createURL(history.context.location) | |
} | |
const history = { | |
// put context on history for use in StaticRouter | |
context: {}, | |
createHref: createHref, | |
action: 'POP', | |
location: stripBasename(basename, createLocation(location)), | |
push: handlePush, | |
replace: handleReplace, | |
go: staticHandler('go'), | |
goBack: staticHandler('goBack'), | |
goForward: staticHandler('goForward'), | |
listen: noop, | |
block: noop, | |
} | |
return history | |
} | |
export default createStaticHistory |
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
import ReactDOMServer from 'react-dom/server' | |
import { Provider } from 'react-redux' | |
import StaticRouter from 'react-router' | |
import { routerMiddleware } from 'react-router-redux' | |
app.use(function handleRequest(ctx) { | |
const history = createStaticHistory(ctx.request.url) | |
const store = makeCreateStore([ | |
...middleware, | |
routerMiddleware(history), | |
])(rootReducer, {}) | |
const html = ReactDOMServer.renderToString( | |
<Provider store={store}> | |
<StaticRouter history={history}> | |
{reactApp} | |
</StaticRouter> | |
</Provider> | |
) | |
if (history.context.url) { | |
ctx.status = 302 | |
ctx.redirect(history.context.url) | |
} else { | |
ctx.response.body = `<!doctype html>${ | |
ReactDOMServer.renderToStaticMarkup(<Html html={html}/>) | |
}` | |
} | |
}) |
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
import React, { PropTypes } from 'react' | |
import { Router } from 'react-router' | |
import createStaticHistory from 'react-router/createStaticHistory' | |
/** | |
* The public top-level API for a "static" <Router>, so-called because it | |
* can't actually change the current location. Instead, it just records | |
* location changes in a context object. Useful mainly in testing and | |
* server-rendering scenarios. | |
*/ | |
class StaticRouter extends React.Component { | |
static propTypes = { | |
history: PropTypes.object, | |
}; | |
static defaultProps = { | |
history: createStaticHistory(), | |
}; | |
static childContextTypes = { | |
router: PropTypes.object.isRequired, | |
} | |
getChildContext() { | |
return { | |
router: { | |
// context needed by history so moved into it | |
// this reference could get lost... | |
staticContext: this.props.history.context, | |
}, | |
} | |
} | |
render() { | |
const { history, ...props } = this.props | |
return <Router {...props} history={history}/> | |
} | |
} | |
export default StaticRouter |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment