A rss template with es6, redux, react-router, material-ui.
Ran into some react server side render issue related to Maerial-ui and more,
took me few days to build it up.
So I turn it into a template for others who also has the requirement about
React Server Side Render.
###NPM
npm install
npm start
###Yarn
// if you don't have one, you should give it a try > <
npm install -g yarn
yarn
npm start
server render without any fetching data or loading data
http://localhost:3000/
fetching data before server render
http://localhost:3000/parks
The story begins at server.js
. Here, we use express
as web framework. When a request comes in, the server passes the request object to match
, which is a function of react-router
, to do the actual routing. The second argument of match
is a callback function.
This callback function does the following:
- Respond to client immediately if there is any error or redirection.
- Access the wrapped react component (in this example app, this is a redux container) and assign it to
comp
. - Access the predefined static function
fetchData
(this is where fetching actually happens) and assign it tofunc
. IffetchData
is not defined, then assign a resolved promise tofunc
. - Execute
func
and chain it with some custom functions and the responding action. By usingrenderToString
, we can export a react component to html string.
// server.js
import express from 'express'
// ...
app.get('*', (req, res) => {
// ...
match({ routes: routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message)
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
const comp = renderProps.components[renderProps.components.length - 1].WrappedComponent
const func = comp.fetchData
? comp.fetchData({ store, limit, offset })
: Promise.resolve()
func.
then(() => store.dispatch(serverRender())).
then(() => {
res.send("<!DOCTYPE html>" +
ReactDOMServer.renderToString(
<MuiThemeProvider muiTheme={ muiTheme }>
<Provider store={ store }>
<RouterContext { ...renderProps } />
</Provider>
</MuiThemeProvider>
)
)
})
} else {
res.status(404).send('Not found')
}
})
})
// ParksContainer.js
class ParksContainer extends Component {
static fetchData = ({ store, limit, offset }) =>
store.dispatch(getList({ limit, offset }))
// ...
}
Thanks to davidjuin0519 for the implementation and example of fetching data.
MIT