Last active
September 30, 2022 03:10
-
-
Save RavenHursT/715a3931c7ffc5a394bb55c7743ef961 to your computer and use it in GitHub Desktop.
React .renderToStaticNodeStream() example w/ redux and react-router
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 ReactDOM from 'react-dom' | |
import { createStore, applyMiddleware } from 'redux' | |
import getRootEpic from '../../store/epics/root.epic' | |
import {createEpicMiddleware} from 'redux-observable' | |
import reduxLogger from 'redux-logger' | |
import { Provider } from 'react-redux' | |
import MainApp from './main-app.component' | |
import { BrowserRouter } from 'react-router-dom' | |
import appReducers from '../../store/reducers' | |
import { CookiesProvider } from 'react-cookie' | |
const hydrateData = window.__HYDRATE_DATA__ | |
delete window.__HYDRATE_DATA__ | |
const store = createStore( | |
appReducers, | |
hydrateData, | |
applyMiddleware(reduxLogger, createEpicMiddleware(getRootEpic())) | |
) | |
ReactDOM.hydrate( | |
<Provider store={store}> | |
<BrowserRouter> | |
<CookiesProvider> | |
<MainApp /> | |
</CookiesProvider> | |
</BrowserRouter> | |
</Provider>, | |
document | |
) |
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 from 'react' | |
import { connect } from 'react-redux' | |
import HeadTag from '../head-tag' | |
import { Route, Switch } from 'react-router-dom' | |
import { withRouter } from 'react-router-dom' | |
import ProtectedRoute from '../protected-route' | |
import { toggleNav } from '../navigation/store/navigation.actions' | |
import ContentArea from '../content-area' | |
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider' | |
import getMuiTheme from 'material-ui/styles/getMuiTheme' | |
import AppBar from 'material-ui/AppBar' | |
import Navigation from '../navigation' | |
import SignIn from '../sign-in' | |
import {reducersMap} from '../../store/reducers/index' | |
import './styles/main-app.scss' | |
const getHydrateState = (props) => Object.keys(props) | |
.filter(key => Object.keys(reducersMap).includes(key)) | |
.reduce((obj, key) => { | |
obj[key] = props[key] | |
return obj | |
}, {}) | |
const MainApp = (props) => { | |
const muiTheme = props.serveRequest ? getMuiTheme( | |
{}, | |
{ | |
userAgent: props.serveRequest.headers[`user-agent`] | |
} | |
) : undefined | |
const hydrateData = JSON.stringify(getHydrateState(props)) | |
return ( | |
<html> | |
<HeadTag title={props.viewTitle} /> | |
<body> | |
<MuiThemeProvider muiTheme={muiTheme} > | |
<Switch> | |
<Route | |
path="/sign-in" | |
exact={true} | |
component={SignIn} /> | |
<Route | |
render={ | |
({ staticContext }) => | |
<div id="main-app"> | |
<AppBar | |
title="HoneyCo: Sage" | |
onLeftIconButtonTouchTap={props.toggleNav} | |
style={{ | |
backgroundColor: `#daa03e` | |
}} | |
/> | |
<div id="content-wrp"> | |
<Switch> | |
<ProtectedRoute | |
path="/" | |
component={ContentArea} /> | |
</Switch> | |
<Navigation open={props.navigation.navOpen}/> | |
</div> | |
</div> | |
} | |
/> | |
</Switch> | |
</MuiThemeProvider> | |
<script dangerouslySetInnerHTML={{__html: `window.__HYDRATE_DATA__ = ${hydrateData}`}} /> | |
<script src="/static/js/bundle.js"></script> | |
</body> | |
</html> | |
) | |
} | |
const mapStateToProps = state => { | |
return { ...state } | |
} | |
export function mapDispatchToProps(dispatch) { | |
return { | |
toggleNav: () => { | |
dispatch(toggleNav()) | |
} | |
} | |
} | |
export default withRouter( | |
connect( | |
mapStateToProps, | |
mapDispatchToProps | |
)(MainApp) | |
) |
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 from 'react' | |
import ReactDomServer from 'react-dom/server' | |
import { StaticRouter } from 'react-router' | |
import { createStore, applyMiddleware } from 'redux' | |
import reduxLogger from 'redux-logger' | |
import { Provider } from 'react-redux' | |
import MainApp from '../components/main-app' | |
import getRootEpic from '../store/epics/root.epic' | |
import { createEpicMiddleware } from 'redux-observable' | |
import appReducer from '../store/reducers' | |
import stream from 'stream' | |
import { CookiesProvider } from 'react-cookie' | |
import Cookies from 'universal-cookie' | |
const docType = `<!DOCTYPE html>` | |
export default async function viewsMiddleware(ctx, next) { | |
if(!ctx.accepts([`html`, `text/html`])) { | |
await next() | |
return | |
} | |
const epicMiddleware = createEpicMiddleware(getRootEpic()) | |
const pass = new stream.PassThrough() | |
const routeCtx = {} | |
const store = createStore( | |
appReducer, | |
applyMiddleware(reduxLogger, epicMiddleware) | |
) | |
ctx.type = `html` | |
ctx.body = pass | |
pass.write(docType) | |
console.dir(ctx.headers, {colors:true, depth:2}) | |
const appStream = ReactDomServer.renderToStaticNodeStream( | |
<Provider store={store}> | |
<StaticRouter location={ctx.request.path} context={routeCtx}> | |
<CookiesProvider cookies={new Cookies(ctx.headers.cookie || ``)}> | |
<MainApp serveRequest={ctx.request} /> | |
</CookiesProvider> | |
</StaticRouter> | |
</Provider> | |
) | |
appStream.pipe(pass, {end: false}) | |
appStream.on(`end`, () => { | |
console.log(`routeCtx => `, routeCtx) | |
ctx.status = routeCtx.status || 200 | |
if (routeCtx.url) { | |
ctx.status = 307 | |
ctx.response.set(`Location`, routeCtx.url) | |
ctx.body = `Temporarily Moved` | |
} | |
pass.end() | |
}) | |
await next() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wrote this year's ago.. I'm sure there's better examples out there now.