Could not find react-redux context value; please ensure the component is wrapped in a <Provider>

喜你入骨 提交于 2021-02-11 12:50:30

问题


I'm trying to do my exportable package in which I create the redux store. This is the code:

import React from "react";
import { Provider } from "react-redux";
import { ErrorPage } from "../components/shared";
import { MyCoreApplication } from "./MyCoreApplication";
import { configureStore } from "../tools/configureStore";
import { createCoreHelp } from "./createCoreHelp";

export const MyCore = ({ withLogs, applicationSagas, applicationReducers, app, cookieInfo }) => {
  const help = createCoreHelp(applicationSagas, applicationReducers, app);
  if (help.error) return <ErrorPage errorMessage={help.error} tooltipMessage={help.tooltip} />;
  else {
    const store = configureStore(withLogs, applicationSagas, applicationReducers);
    return (
      <Provider store={store}>
        <MyCoreApplication app={app} cookieInfo={cookieInfo} />
      </Provider>
    );
  }
};

MyCoreApplication is the same:

import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { IntlProvider } from "react-intl";
import { BrowserRouter as Router } from "react-router-dom";
import { CookieBar, ErrorPage, LoadingSpinner, Notification } from "../components/shared";
import { getConfig, getConfigStore, fetchConfigEnded, isMobileMode, setMobileMode } from "../modules/configuration";
import { getLocale, setLocale, getMessages, fetchMessages } from "../modules/language";

export const MyCoreApplication = ({ app, cookieInfo }) => {
  const dispatch = useDispatch();
  const config = useSelector(getConfigStore);
  const configLoaded = useSelector(fetchConfigEnded);
  const mobileMode = useSelector(isMobileMode);
  const messages = useSelector(getMessages);
  const locale = useSelector(getLocale);

  const actions = {
    getConfig: () => dispatch(getConfig()),
    setLocale: (locale) => dispatch(setLocale(locale)),
    fetchMessages: (locale) => dispatch(fetchMessages(locale)),
    setMobileMode: (checkMobile) => dispatch(setMobileMode(checkMobile)),
  };

  if (config === null && !configLoaded) dispatch(getConfig());
  else {
    if (!locale && config) actions.setLocale(config.defaultLanguage);
  }

  return config ? (
    <IntlProvider messages={messages} locale={locale} defaultLocale={config.defaultLanguage}>
      <Notification />
      <Router>{app}</Router>
      {cookieInfo && cookieInfo.useCookie && cookieInfo.infoLink && <CookieBar infoLink={cookieInfo.infoLink} />}
    </IntlProvider>
  ) : configLoaded ? (
    <ErrorPage />
  ) : (
    <LoadingSpinner />
  );
};

The goal of my package is to build a library which create redux store receiving sagas and reducer from the custom application. In this mode a developer who use this library hasn't to create the store because module has already done. In this project I use webpack and after run build and pack npm commands I've got a .tgz file that I use in a create-react-app project as a dependency. In this create-react-app project I use my package in the following mode:

import React from "react-dom";
import ReactDOM from "react-dom";
import { MyCore } from "my_core";
import { appSagas } from "./store/appSagas";
import { appReducers } from "./store/appReducers";
import { App } from "./container/App";
import "./styles/index.scss";

const wrapper = document.getElementById("container");
wrapper &&
  ReactDOM.render(
    <MyCore
      withLogs={true}
      applicationSagas={appSagas}
      applicationReducers={appReducers}
      app={<App />}
    />,
    wrapper
  );

And this is the App code:

import React from "react";
import { Layout } from "antd";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { MyHeader as Header } from "../components/MyHeader.jsx";
import { Components } from "my_core";

const { MyFooter: Footer } = Components;

const { Content } = Layout;

export const App = () => (
  <Layout>
    <Router>
      <Header />
      <Content>
        <Switch>
          <Route exact path="/">
            hello
          </Route>
        </Switch>
        <Footer />
      </Content>
    </Router>
  </Layout>
);

Finally, inside MyHeader I use useSelector as the following code shows:

import React from "react";
import { useSelector } from "react-redux";
import { Utility } from "my_core";

const { configUtils } = Utility;

export const MyHeader = () => {
  const mobileMode = useSelector(configUtils.isMobileMode);

  return mobileMode ? <div>Mobile Header</div> : <div>Desktop Header</div>;
};

When I start the create-react-app project I encounter this error:

useSelector() Error: Could not find react-redux context value; please ensure the component is wrapped in a <Provider>

The same identical code, if written inside MyCore package project, works fine. How can I solve this problem?


回答1:


At this link github.com/iBobo5/myCore.git you can find myCore project. It's enough to run npm install and npm run export to obtain .tgz file. Once it has been created copy in a create-react-app "test" project and install it with react and react-dom dependencies. Other dependencies are installed by the library. Inside "test" project try to replace the import as shown above and inside a component use useSelector or useDispatch. In this way you could be able to reproduce my issue




回答2:


The problem is probably that you have react-redux as a dependency rather than a peerDependency in your package.json. So you will potentially have two versions in the application in which the library is consumed, which causes the bug you described.



来源:https://stackoverflow.com/questions/65610678/could-not-find-react-redux-context-value-please-ensure-the-component-is-wrapped

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!