React + Redux + SSR:仅在直接导航到连接的组件时找不到存储

时间:2019-02-17 23:20:42

标签: redux react-redux react-router serverside-rendering

我对使用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);

[...]

3 个答案:

答案 0 :(得分:1)

如果通过上下文或道具公开商店,则可以从子组件访问商店。
您也可以通过将商店添加到window对象中来公开它,但这不是一个好习惯,因为站点中的每个访问者都可以查看和更改商店。 (如果您不关心Redux商店的安全性,可能会很有用。)
您还可以根据此答案的建议使用设置器: Redux state value globally

redux提供程序通过上下文使商店可用于所有子项。

  

那个Provider标签呈现了您的父组件,我们称它为App   组件,进而呈现   应用。

     

当我们使用connect()包装组件时,这是关键部分   函数,该connect()函数期望看到一些父组件   带有提供者标签的层次结构中。

Invariant Violation: Could not find "store" in either the context or props of "Connect(SportsDatabase)"

因此,根据链接的答案,您的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。

如有任何疑问或澄清,请回复。