我对使用React和Redux的SSR相对较新,所以我认为我犯了一个简单的错误,这反映出我对底层框架缺乏理解。但是,我要把头伸到墙上,所以去了。希望有人能帮忙。
如果我尝试直接导航到根页面(/),则会收到错误null
。就我而言,Could not find "store" in the context of "Connect(Home)"
包含我的共享导航逻辑和全局内容,并且(/)呈现一个App
组件。如果我导航到未连接到Redux的页面(例如服务条款),然后导航到我的主页,则该页面呈现完美。我以为这是某种服务器端路由问题,但是我已经阅读了所有可以在网上找到的内容,尝试了状态/存储/上下文处理的每种可能排列方式,但无法解决。
这是我的代码的骨架。
renderer.js
Home
configureStore.js
[...]
const modules = [];
const routerContext = {};
const bundle = (
<Loadable.Capture report={m => modules.push(m)}>
<ReduxProvider store={store}>
<StaticRouter location={req.baseUrl} context={routerContext}>
<CookiesProvider cookies={req.universalCookies}>
<App />
</CookiesProvider>
</StaticRouter>
</ReduxProvider>
</Loadable.Capture>
);
const html = ReactDOMServer.renderToString(bundle);
if (routerContext.url) {
redirect(301, routerContext.url);
}
// inject into HTML
[...]
index.js (客户端)
[...]
const createStoreWithMiddleware = compose(applyMiddleware(ReduxThunk))(createStore);
export default function configureStore(initialState = {}) {
return createStoreWithMiddleware(rootReducer, initialState);
};
app.js (“ /”呈现Home组件)
const store = configureStore( window.__REDUX_STATE__ || {} );
const AppBundle = (
<ReduxProvider store={store}>
<BrowserRouter>
<CookiesProvider>
<App />
</CookiesProvider>
</BrowserRouter>
</ReduxProvider>
);
window.onload = () => {
Loadable.preloadReady().then(() => {
ReactDOM.hydrate(
AppBundle,
document.getElementById('root')
);
});
};
home.js
[...]
export default withCookies(App);
[...]
答案 0 :(得分:1)
如果通过上下文或道具公开商店,则可以从子组件访问商店。
您也可以通过将商店添加到window对象中来公开它,但这不是一个好习惯,因为站点中的每个访问者都可以查看和更改商店。 (如果您不关心Redux商店的安全性,可能会很有用。)
您还可以根据此答案的建议使用设置器:
Redux state value globally
redux提供程序通过上下文使商店可用于所有子项。
那个Provider标签呈现了您的父组件,我们称它为App 组件,进而呈现 应用。
当我们使用connect()包装组件时,这是关键部分 函数,该connect()函数期望看到一些父组件 带有提供者标签的层次结构中。
因此,根据链接的答案,您的Home组件必须在其上下文中具有Provider或商店本身,这可能是导致您出错的原因。
答案 1 :(得分:1)
我终于确定了问题所在。我正在运行Express服务器,以与Node客户端同时托管服务器渲染的页面。不幸的是,服务器正在创建一个React实例,而客户端正在创建另一个React实例。结果,即使代码看起来正确,我的Redux存储也没有沿同一个React上下文的组件层次结构传递。
请我永远调试和识别。 This article最终为我指明了正确的方向……但是由于React调试器无法在服务器渲染的应用程序上运行,因此并没有完全解决问题。
有多种可能的解决方案。就我而言,最简单的解决方案是整合我在客户端和服务器之间的所有依赖关系,从而隐式删除所有冗余的React实例。
真的希望这个答案对其他人有帮助,因为我花了一个多月的时间尝试每周对其进行一次或两次调试。
答案 2 :(得分:0)
在服务器端,您还需要创建商店,其状态被视为客户端渲染的初始状态。在客户端,我可以看到您已完成此操作:
const store = configureStore( window.__REDUX_STATE__ || {} )
类似的事情也需要在服务器端完成。
在服务器端,您需要执行store = createStore(rootReducer)
来创建商店,此商店将在<ReduxProvider store={store}>
中用于render.js。
如有任何疑问或澄清,请回复。