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

React + Redux + SSR: Cannot find store only when navigating directly to connected component

我对使用 React 和 Redux 的 SSR 比较陌生,所以我认为我犯了一个简单的错误,这反映了我对底层框架缺乏了解。但是,我即将把我的头穿过一堵墙,所以就这样吧。希望有人能帮忙。

如果我尝试直接导航到根页面 (/),我会收到错误 Could not find "store" in the context of "Connect(Home)"。在我的例子中,App 包含我共享的导航逻辑和全局内容,并且 (/) 呈现一个 Home 组件。如果我导航到一个没有连接到 Redux 的页面(例如服务条款),然后导航到我的主页,它会完美呈现。我认为这是某种服务器端路由问题,但我已经阅读了我可以在网上找到的所有内容,尝试了状态/存储/上下文处理的所有可能排列,但我无法解决它。

这是我的代码的框架。

renderer.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

[...]

configureStore.js

[...]

const createStoreWithMiddleware = compose(applyMiddleware(ReduxThunk))(createStore);

export default function configureStore(initialState = {}) {
    return createStoreWithMiddleware(rootReducer, initialState);
};

index.js(客户端)


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')
        );
    });
};

app.js(“/”渲染Home组件)

[...]

export default withCookies(App);

[...]

home.js

[...]

export default connect(mapStateToProps)(Home);

[...]

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

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

That Provider tag renders your parent component, lets call it the App component which in turn renders every other component inside the application.

Here is the key part, when we wrap a component with the connect() function, that connect() function expects to see some parent component within the hierarchy that has the Provider tag.

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

因此,根据链接的答案,您的 Home 组件必须在其上下文中有一个 Provider 或商店本身,这可能是您出错的原因。

在服务器端,您还需要创建您的商店,其状态被视为客户端呈现的初始状态。在客户端,我可以看到你已经这样做了:

const store = configureStore( window.__REDUX_STATE__ || {} )  

服务器端也需要做类似的事情。

在服务器端,您需要执行 store = createStore(rootReducer) 来创建此处 <ReduxProvider store={store}> 在 rendered.js 中使用的商店。

如有任何疑问或说明,请回复。

我终于找到问题所在了。我是 运行 一个 Express 服务器,用于与 Node 客户端同时托管服务器呈现的页面。不幸的是,服务器正在创建一个 React 实例,而客户端正在创建另一个 React 实例。结果,即使代码看起来正确,我的 Redux 存储并没有被传递到相同 React 上下文的组件层次结构中。

花了我很长时间调试和识别。 This article 终于为我指明了正确的方向......但它并没有让我一路走来,因为 React 调试器不能在服务器呈现的应用程序上工作。

这个问题有多种可能的解决方案。就我而言,最简单的解决方案是整合我在客户端和服务器之间的所有依赖关系,这隐式地删除了所有冗余的 React 实例。

真的希望这个答案对其他人有所帮助,因为我花了一个多月的时间尝试每周每天调试一次或两次。