Open zdila opened 5 years ago
Minimal testcase:
import ReactDOMServer from 'react-dom/server';
import React from 'react';
import { Provider } from 'react-redux';
import { ConnectedRouter, push } from 'connected-react-router';
import { createStore } from 'redux';
import createHistory from 'history/createMemoryHistory';
const history = createHistory();
const store = createStore(() => {});
console.log('DUMP', ReactDOMServer.renderToString((
<Provider store={store}>
<ConnectedRouter history={history}>
<div>Hello</div>
</ConnectedRouter>
</Provider>
)));
You may want to use <StaticRouter>
on the server side. Here's an example from a repo that adds SSR to a non-ejected CRA starter app. https://github.com/cereallarceny/cra-ssr/blob/master/server/loader.js
I'm facing the same issue without SSR.
Mee too
Me too, without SSR
same issue when using ssr
I'm using the connected-react-router v6 and still having the issue using SSR.
Just moved off of react-router to connected-react-router v6.(.3..2). We have an SSR setup and are running into the same issue.
When using SSR with
ReactDOMServer.renderToString
I get following exception:Invariant Violation: Could not find "store" in the context of "Connect(ConnectedRouterWithContext)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(ConnectedRouterWithContext) in connect options. at invariant (/home/user/app/node_modules/invariant/invariant.js:40:15) at Connect.renderWrappedComponent (/home/user/app/node_modules/react-redux/lib/components/connectAdvanced.js:162:32) at ReactDOMServerRenderer.render (/home/user/app/dist/node_modules/react-dom/cjs/react-dom-server.node.development.js:2494:55) at ReactDOMServerRenderer.read (/home/user/app/dist/node_modules/react-dom/cjs/react-dom-server.node.development.js:2357:19) at Object.renderToString (/home/user/app/dist/node_modules/react-dom/cjs/react-dom-server.node.development.js:2729:25) at renderToString (/home/user/app/dist/server/webpack:/src/server/indexServer.js:220:18)
Dependencies:
"connected-react-router": "6.0.0", "react": "16.7.0", "react-dom": "16.7.0", "react-redux": "6.0.0", "react-router-dom": "4.3.1", "redux": "4.0.1",
Compoents:
<Provider store={store}> <ErrorCatcher> <ConnectedRouter history={history}> <Switch> <Route path="/recorder/" component={Recorder} /> <Route path="/" component={Regular} /> </Switch> </ConnectedRouter> </ErrorCatcher> </Provider>
Rendering client-side only works.
@zdila My solution is following:
In the store:
export const getStoreConfiguration = (preloadedState) => {
const middlewares = [];
let history;
let reducers = {
init(state, action) {
return { ...state, ...action.payload };
},
};
if (isClient()) {
history = createBrowserHistory();
reducers.router = connectRouter(history);
middlewares.push(routerMiddleware(history));
}
return {
store: createStore(
combineReducers(reducers),
preloadedState,
composeEnhancer(applyMiddleware(...middlewares))
),
history,
};
};
isClient
export default () => {
try {
if (window && window.document && window.document.createElement) return true;
return false;
} catch (err) {
return false;
}
}
in the client
const { store, history } = getStoreConfiguration(preloadedState);
<Provider store={store}>
<ConnectedRouter history={history}>
<ClientApp />
</ConnectedRouter>
</Provider>,
The key is check the client or server, for difference env to create the store and history.
@zsirfs I am using solution provided in https://github.com/supasate/connected-react-router/issues/212#issuecomment-449390810. But still old approach used to work in older versions of connected-react-router (react-router-redux).
@zsirfs I am using solution provided in #212 (comment). But still old approach used to work in older versions of connected-react-router (react-router-redux).
Ok, I am using my solution work well.
I have an older project from 2015, but got it working. Newer projects would probably work the same.
I had to use StaticRouter
server-side 👎, but it worked when I made connectedRouter
optional in combineReducers
:
const createRootReducer = history => (
combineReducers({
collapsibleMenu: collapsibleMenuReducer,
pageMeta: pageMetaReducer,
playback: playbackReducer,
...(
history
&& { router: connectRouter(history) }
),
showSongs: showSongsReducer,
})
)
Then, in my server renderer, I did this:
const context = {}
const store = compose()(createStore)(createRootReducer())
const renderedContent = renderToString(
<Provider store={store}>
<StaticRouter
context={context}
location={req.url}
>
<Pages />
</StaticRouter>
</Provider>
)
const renderedPage = renderSite(renderedContent, store.getState())
if (context.url) {
console.log('redirect');
res.writeHead(302, { Location: context.url })
res.end()
}
else {
console.log(req.url);
res.send(renderedPage).end()
}
When using SSR with
ReactDOMServer.renderToString
I get following exception:Dependencies:
Compoents:
Rendering client-side only works.