diff --git a/README.md b/README.md
index 55f55ac3..227506cb 100644
--- a/README.md
+++ b/README.md
@@ -59,6 +59,10 @@ Install `redux-first-router` and its peer dependency `history` plus our small `<
yarn add history redux-first-router redux-first-router-link
```
+**Demo App:**
+https://github.com/faceyspacey/redux-first-router-demo
+
+
## Motivation - What Routing in Redux is Meant To Be
To automate routing. To be able to use Redux *as is* while keeping the URL in the address bar in sync.
@@ -225,7 +229,8 @@ After the dispatch of a matching action, a thunk (if provided) will be called, a
```javascript
const userThunk = async (dispatch, getState) => {
const { slug } = getState().location.payload
- const user = await fetch(`/api/user/${slug}`)
+ const data = await fetch(`/api/user/${slug}`)
+ const user = await data.json()
const action = { type: 'USER_FOUND', payload: { user } }
dispatch(action)
diff --git a/docs/server-rendering.md b/docs/server-rendering.md
index 50097ec1..b7215d55 100644
--- a/docs/server-rendering.md
+++ b/docs/server-rendering.md
@@ -1,14 +1,15 @@
# Server Side Rendering (using thunk)
Ok, this is the biggest example here, but given what it does, we think it's extremely concise and sensible. Since the middleware handles the actions it receives asyncronously, on the server you simply `await` the result of a possible matching thunk:
-```javascript
-import express from 'express'
+
+*configureStore.js:*
+```js
import { createStore, applyMiddleware, compose } from 'redux'
import createHistory from 'history/createMemoryHistory'
-import { connectRoutes, NOT_FOUND } from 'redux-first-router'
+import { connectRoutes } from 'redux-first-router'
-const render = async (req, res) => {
- const history = createHistory({
- initialEntries: [req.path], // match initial route to express path
+export function configureStore(path) {
+ const history = createHistory({
+ initialEntries: [path] // match initial route to express path
})
const routesMap = {
@@ -17,7 +18,8 @@ const render = async (req, res) => {
path: '/entity/:slug',
thunk: async (dispatch, getState) => {
const { slug } = getState().location.payload
- const entity = await fetch(`/api/entity/${slug}`)
+ const data = await fetch(`/api/entity/${slug}`)
+ const entity = await data.json()
const action = { type: 'ENTITY_FOUND', payload: { entity } } // you handle this action type
dispatch(action)
@@ -27,7 +29,21 @@ const render = async (req, res) => {
const { reducer, middleware, enhancer, thunk } = connectRoutes(history, routesMap) // notice `thunk`
const rootReducer = combineReducers({ location: reducer })
- const store = createStore(rootReducer, compose(enhancer, applyMiddleware(middleware)))
+
+ return createStore(rootReducer, compose(enhancer, applyMiddleware(middleware)))
+}
+```
+
+*serverRender.js:*
+```javascript
+import serialize from 'serialize-javascript'
+import { NOT_FOUND } from 'redux-first-router'
+import configureStore from './configureStore'
+import App from './components/App'
+import Html from './components/Html'
+
+export default async function serverRender(req, res) => {
+ const store = configureStore(req.path)
// using redux-thunk perhaps request and dispatch some app-wide state as well, e.g:
// await Promise.all([ store.dispatch(myThunkA), store.dispatch(myThunkB) ])
@@ -39,28 +55,42 @@ const render = async (req, res) => {
return res.redirect(302, '/unavailable')
}
- const state = JSON.stringify(store.getState())
+ const app = ReactDOM.renderToString(