React-router: SSR Issues with ConnectedRouter and server-side Redux.

Created on 11 Aug 2017  路  4Comments  路  Source: ReactTraining/react-router

Version

react-router 4.1.2
react-router-redux next

Steps to reproduce

Set up SSR using ConnectedRouter to reflect state in the store.

    if (!Object.keys(cachedRoutes).includes(ctx.path)) {
      debug.log('We are going to do full SSR, here...')

      const { store, client, history } = await configureRedux(ctx)

      const context = {}
      const component = (
        <ApolloProvider store={store} client={client}>
          <ConnectedRouter location={ctx.path} history={history}>
            <ActionContainer />
          </ConnectedRouter>
        </ApolloProvider>
      )

      try {
        const root = await renderToStringWithData(component)
        const apolloState = client.store.getState()['apollo'].data
        const reduxState = store.getState()
        const html = <Html assets={assets} root={root} apolloState={apolloState} reduxState={reduxState} />
        cachedRoutes[ctx.path] = `<!DOCTYPE html>\n${ReactDOM.renderToStaticMarkup(html)}`
      }
      catch(e) {
        debug.error('RENDERING ERROR:', e)
        ctx.status = 500
        return
      }
    }
    ctx.status = 200
    ctx.body = cachedRoutes[ctx.path]

Expected Behavior

After rendering the root, root should contain the appropriate route, which it doesn't, and store.getStore()['router'] should contain a location object with the correct information, which it doesn't.

Actual Behavior

The wrong path is being rendered and reported mismatch on client:

connectedrouter ssr issue -- wrong path rendered

ssr connectedrouter issue

And above you can see that the location object is indeed populated with information, but the issue is that this is the wrong path. In this instance, the path is:

actual path

Additional Notes

I have tried using StaticRouter, but this is not rendering the markup correctly and of course does not update the store.

For instance, with StaticRouter, I am getting these SSR errors client side:

staticrouter ssr client side irregularity

Also, the context is not being updated with any information--is this up to components? This would put a heavy burden on the developer to essentially support two instances, where it seems to me that ConnectedRouter being used with createMemoryHistory(ctx.url) and server-side redux should suffice, no?

staticrouter context empty

Most helpful comment

Woot, woot! I got it to work! I needed to add the following to the createMemoryHistory(...) call:

const memoryHistory = createMemoryHistory({
  initialEntries: [ctx.path],
})

Et voil脿!! No more SSR issue with ConnectedRouter and state are correctly handled.

All 4 comments

Woot, woot! I got it to work! I needed to add the following to the createMemoryHistory(...) call:

const memoryHistory = createMemoryHistory({
  initialEntries: [ctx.path],
})

Et voil脿!! No more SSR issue with ConnectedRouter and state are correctly handled.

@Panoplos I am faing some weird problem with react-router-redux and SSR
Turns out that the SSR seems to be working but on the client the rendering fails

client.js

import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import { ConnectedRouter } from 'react-router-redux';
import _ from 'lodash';
import createHistory from 'history/createBrowserHistory';
import routes from './routes';
import configureStore from './store';
import './styles/style.css';

const element = document.getElementById('app-container');

const initState = window.__PRELOADED_STATE__;
const history = createHistory();
const store = configureStore(history, initState);

render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <Switch>{routes.map(route => <Route key={_.uniqueId()} exact={route.exact || false} path={route.path} render={props => (<route.component {...props} routes={route.routes || null} />)} />)}</Switch>
    </ConnectedRouter>
  </Provider>,
  element,
);

store.js

import { routerMiddleware } from 'react-router-redux';
import thunk from 'redux-thunk';
import { createStore, compose, applyMiddleware } from 'redux';
import rootReducer from './reducers';

const composeEnhancers = process.env.NODE_ENV !== 'production' && typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose;

export default (history, initState) => {
  const store = createStore(
    rootReducer,
    initState,
    composeEnhancers(applyMiddleware(thunk, routerMiddleware(history))),
  );

  return store;
};

The error I keep getting is this
screen shot 2017-10-05 at 7 52 23 pm

@rahulbasu710 Not sure I can help you, as I am using ApolloProvider, not react-redux's Provider.

Not a problem. Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andrewpillar picture andrewpillar  路  3Comments

wzup picture wzup  路  3Comments

maier-stefan picture maier-stefan  路  3Comments

stnwk picture stnwk  路  3Comments

hgezim picture hgezim  路  3Comments