Version: 4.1.1
I'm using ConnectedRouter on client and want to have isomorphic access to location and control over it.
StaticRouter is really great!And he keeps isomorphic code working over environments!
<StaticRouter keeps history freezed and unchanged (this is very important for server-side rendering)<Redirect working context.urlIf we need to work with location from redux-store (e.g. is redux-saga) on server - there is no location in store
Also if we dispatch and push or redirect action - they will not be handled, because StaticRouter history cannot be provided into routerMiddleware
I reviewed comment from @timdorr in #5475.
As i understand, he recommends to write our own actions to handle push/replace on server
But I do not agree with this comment.
We already have history and routing via Router and ConnectedRouter
So why we need to write different code for client-side and for server-side, if this code do the same things?
The only difference between client and server code is how it will be handled on top level of application in different environments
(e.g. window.history.replaceState vs response.redirect)
I think this problems can be solved by writing modified ConnectedStaticRouter
This is how it may looks on server:
// staticHistory currently implemented inside `StaticRouter` and must be extracted
// https://git.io/vb97k
import createHistory from 'history/createStaticHistory'
// Some express.js middleware
function renderReactPage(req, res) {
const routerContext = {}
// static router context need to be provided into staticHistory (but now is hardcored inside StaticRouter)
const history = createHistory(routerContext)
// `react-router-redux` reducer and middleware declaration still same as currently implemented
const middleware = routerMiddleware(history)
const store = createStore(
combineReducers({ router: routerReducer }),
applyMiddleware(middleware)
)
const html = renderToString(
<Provider store={store}>
<ConnectedStaticRouter location={url} context={routerContext} staticHistory={history}>
<App />
</ConnectedStaticRouter>
</Provider>
)
if (routerContext.url) return res.redirect(301, routerContext.url)
res.send(html)
}
Even if routerContext is useless for ConnectedStaticRouter:
staticHistory functionality because it guarantees that the match of some <Route can't change its match to another <Route during server renderRelates to #5475 #5333 #4892
I'll be happy to make PR, if we find compromise way to improve router<->redux connection for SSR
If we need to work with location from redux-store (e.g. is redux-saga) on server - there is no location in store
Yes, there is. Traditionally, this is available at req.url in Express and similar servers. You would initialize your history with this location already provided. You can also dispatch this into the store so the two are in sync.
You should be using <StaticRouter> for this. A syncing router is not needed, as you can't re-render on the server side so there is no ability to react to a change in the location, other than handling that outside of the React renderToString context.
@timdorr Yep, its not so hard to dispatch LOCATION_CHANGE action to sync history state, but
StaticRouterand we're forced to create second instance of history #4892Also you probably forgot about <Redirect and dispatch(replace(…)) problem
StaticRouter does not support dispatch(replace(…))ConnectedRouter on server-side-render does not support <Redirect and replace(…) and static historyThis is the reason to improve SSR
Most helpful comment
@timdorr Yep, its not so hard to dispatch
LOCATION_CHANGEaction to sync history state, butStaticRouterand we're forced to create second instance of history #4892Also you probably forgot about
<Redirectanddispatch(replace(…))problemStaticRouterdoes not supportdispatch(replace(…))ConnectedRouteron server-side-render does not support<Redirectandreplace(…)and statichistoryThis is the reason to improve SSR