supasate / connected-react-router

A Redux binding for React Router v4
MIT License
4.73k stars 593 forks source link

Getting error after upgraded connected-react-router to 6.5.0 and react-redux to 7.1.0 #330

Open prepaka opened 5 years ago

prepaka commented 5 years ago

Last week I upgrade router related packages in my project after that, I am getting 2 errors while running the project.

Packages which are updated from and to versions

"connected-react-router": **"6.5.0"**, Upgraded from **"5.0.1"**
"react": **"16.8.6"**, Upgraded from **"16.8.2"**
"react-dom": **"16.8.6"**, Upgraded from **"16.8.2"**
"react-redux": **"7.1.0"**, Upgraded from **"5.1.1"**
"react-router-dom": **"5.0.1"**, Upgraded from **"4.3.1"**

The error which I am getting

  1. Uncaught Invariant Violation: Could not find "store" in either the context or props of "Connect(t)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(t)"

  2. Uncaught Error: Invariant failed: You should not use <withRouter(InjectIntl(Component)) /> outside a

image

Before upgrading everything is working fine.

App.js

import React from 'react'; import { Provider } from 'react-redux'; import { IntlProvider, addLocaleData } from 'react-intl'; import { browserHistory } from ; import en from 'react-intl/locale-data/en'; import xh from 'react-intl/locale-data/xh'; import initialState from './state/initialState'; import { configureStore } from './store/configureStore'; import RestApi from './services/RestApi'; import AppContainer from './components/AppContainer'; import { findUserLocale } from './i18n/i18n';

// If needed can pass initialState to configureStore const history = browserHistory; const store = configureStore(initialState, history); RestApi.store = store; addLocaleData([...en, ...xh]); const locale = findUserLocale();

let messages; try { messages = require(./i18n/${locale}.json); // eslint-disable-line } catch (e) { messages = require('./i18n/en-US.json'); // eslint-disable-line global-require } const App = () => (

);

export default App;

AppContainer.js

only required code copied here.

  <ConnectedRouter history={history}>
    <App inline={true} centered={false}>
           <div className='hercules-page idi-page'>
              <HeaderPanel title={title} />
              <Switch>
                <Route  />
                ... routings code
                <Route path='*' component={NotFound} />
              </Switch>
            </div>
          </Split>
    </App>
  </ConnectedRouter>

Do I need to pass anything to Provider and ConnectedRouter according to connected-react-router v6.5.0 to run properly?

Please let me know how to fix these 2 issues.

Larsrdev commented 5 years ago

We have a similiar issue:

We updated from - to "react-redux": from "5.0.7" to "7.1.0", "react-router": from "4.3.1" to "5.0.1", "react-router-dom": from "4.3.1" to "5.0.1", "connected-react-router": from "4.4.1" to "6.5.0",

React were not updated during the process: "react": "16.8.6", "react-dom": "16.8.6",

This is some part of our code:

const reducers= combineReducers({
    router: connectRouter(history),
    ...someOtherReducers...
});
const history = createBrowserHistory();
const routerMw = routerMiddleware(history);
let middleware = [routerMw, someOtherMiddlewares];
appliedMiddleware = compose(appliedMiddleware);
const store = createStore(reducers, undefined, appliedMiddleware);

render((
        <Provider store={store}>
            <ConnectedRouter history={history}>
                 <Route component={withTracker(AppConnected)}/>
            </ConnectedRouter>
        </Provider>
    ),
    document.getElementById('app') as HTMLElement
);

This works pretty well on our local build with the libs code from the node_modules directory. But our deployment build fails when using packages from CDN (unpkg): image

We managed to find out this Problem and added a context to the Provider and ConnectedRouter:

render((
        <Provider store={store} context={ReactReduxContext}>
            <ConnectedRouter history={history} context={ReactReduxContext}>
                <Route component={withTracker(AppConnected)}/>
            </ConnectedRouter>
        </Provider>
    ),
    document.getElementById('app') as HTMLElement
);

This also works with node_modules libs but fails with another error in production build: image

Thats odd, because we use a Connected Router?! In spite of all we wrapped the Route component in a Router:

render((
        <Provider store={store} context={ReactReduxContext}>
            <ConnectedRouter history={history} context={ReactReduxContext}>
                <Router history={history}>
                    <Route component={withTracker(AppConnected)}/>
                </Router>
            </ConnectedRouter>
        </Provider>
    ),
    document.getElementById('app') as HTMLElement
);

Does not look right. But still works in local mode with node_modules, but also fails with CDN packages: image

We see no other way to downgrade back to older versions. Have we missed something? Is there a problem on cdn packages? Did we make a mistake after updating?

Thanks a lot :)

favna commented 5 years ago

Going from 6.4.0 to 6.5.0 as well as react-redux@^6 to react-redux@^7.1.0 and I had a flawless upgrade. These are my most important diffs:

Diff for package.json:

 "dependencies": {
-    "@material-ui/core": "^4.1.3",
+    "@material-ui/core": "^4.2.0",
-    "connected-react-router": "^6.4.0",
+    "connected-react-router": "^6.5.0",
-    "i18next": "^17.0.4",
+    "i18next": "^17.0.6",
-    "react-i18next": "^10.11.2",
-    "react-redux": "^6",
+    "react-i18next": "^10.11.4",
+    "react-redux": "^7.1.0",
-    "redux": "^4.0.1",
+    "redux": "^4.0.2",
-    "redux-saga": "^1.0.4",
+    "redux-saga": "^1.0.5",
  },
  "devDependencies": {
-    "@babel/core": "^7.4.5",
-    "@babel/preset-env": "^7.4.5",
+    "@babel/core": "^7.5.0",
+    "@babel/preset-env": "^7.5.3",
-    "@types/classnames": "^2.2.8",
+    "@types/classnames": "^2.2.9",
-    "@types/enzyme": "^3.9.4",
+    "@types/enzyme": "^3.10.1",
-    "@types/node": "^12.0.10",
+    "@types/node": "^12.6.1",
-    "@types/react": "^16.8.22",
+    "@types/react": "^16.8.23",
-    "@types/react-redux": "^6",
-    "@types/react-router": "^5.0.2",
+    "@types/react-redux": "^7.1.1",
+    "@types/react-router": "^5.0.3",
-    "@types/uuid": "^3.4.4",
-    "@types/yup": "^0.26.18",
+    "@types/uuid": "^3.4.5",
+    "@types/yup": "^0.26.21",
-    "typescript": "^3.5.2",
+    "typescript": "^3.5.3",
  }

Diff for src/App.tsx (our component which holds all the providers)

- import { Provider } from 'react-redux';
+ import { Provider, ReactReduxContext } from 'react-redux';
import React, { FC } from 'react';
import { I18nextProvider } from 'react-i18next';
import { SnackbarProvider } from 'notistack';
import ConnectedHeader from 'containers/Header';
import { ConnectedRouter } from 'connected-react-router';
import configureStore, { history } from 'config/store';
import CssBaseline from '@material-ui/core/CssBaseline';
import { createMuiTheme, MuiThemeProvider, Theme } from '@material-ui/core/styles';
import { StylesProvider } from '@material-ui/styles';
import i18n from 'config/i18n';

const App: FC = () => {
  const initialState = {} as any;
  const store = configureStore(initialState);

  return (
-    <Provider store={store}>
+    <Provider store={store} context={ReactReduxContext}>
      <StylesProvider injectFirst>
        <I18nextProvider i18n={i18n}>
          <MuiThemeProvider theme={createTheme}>
            <SnackbarProvider maxSnack={4}>
-              <ConnectedRouter history={history}>
+              <ConnectedRouter history={history} context={ReactReduxContext}>
                <CssBaseline />
                <ConnectedHeader />
              </ConnectedRouter>
            </SnackbarProvider>
          </MuiThemeProvider>
        </I18nextProvider>
      </StylesProvider>
    </Provider>
  );
};
export default App;

For reference's sake this is how App is loaded in index.tsx:

// tslint:disable:ordered-imports
import 'core-js';
import 'react-app-polyfill/ie11';
import React from 'react';
import ReactDOM from 'react-dom';
import App from 'App';
import 'styles/styles.scss';
// tslint:enable:ordered-imports

const target = document.querySelector('#root');
ReactDOM.render(<App/>, target);

And some other parts of code:

from src/store/index.ts

import {
  connectRouter, go, goBack, goForward,
  push, replace, RouterState
} from 'connected-react-router';
import { History } from 'history';
import { combineReducers } from 'redux';
import { all, fork } from 'redux-saga/effects';
import SnackbarReducer from './snackbars/snackbarReducer';
import { SnackbarState } from './snackbars/snackbarTypes';
import * as snackbarActions from 'store/snackbars/snackbarActions';
import { ActionType } from 'typesafe-actions';

const routerActions = {
  push: typeof push,
  replace: typeof replace,
  go: typeof go,
  goBack: typeof goBack,
  goForward: typeof goForward,
};

export type ApplicationState = Readonly<{
  router: RouterState;
  notifications: SnackbarState;
  // other states
}>;

export function* rootSaga () {
  yield all([fork(/* stubbed */), fork(/* stubbed */)]);
}

export const rootActions = {
  router: routerActions,
  notifications: snackbarActions,
// other actions
};

export type RootAction = ActionType<typeof rootActions>;

// @ts-ignore
export default (history: History) => combineReducers<ApplicationState>({
  router: connectRouter(history),
  notifications: SnackbarReducer,
  // other reducers 
});

src/config/store.ts

import { routerMiddleware } from 'connected-react-router';
import { createBrowserHistory } from 'history';
import { AnyAction, applyMiddleware, createStore, Middleware, Store } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';
import { createLogger } from 'redux-logger';
import createSagaMiddleware, { SagaMiddleware } from 'redux-saga';
import createRootReducer, { ApplicationState, rootSaga } from '../store';

interface HotNodeModule extends NodeModule {
  hot: any;
}

export const history = createBrowserHistory();

export default (initialState: ApplicationState): Store<ApplicationState> => {
  const composeEnhancers = composeWithDevTools({});
  const sagaMiddleware = createSagaMiddleware();
  const middlewares: (SagaMiddleware | Middleware)[] = [routerMiddleware(history), sagaMiddleware];
  const logger = createLogger({
    collapsed: (getState: () => any, action: AnyAction, logEntry: any) => !logEntry.error,
  });

  if (process.env.NODE_ENV === `development`) {
    middlewares.push(logger);
  }

  const store = createStore(
    createRootReducer(history),
    initialState,
    composeEnhancers(applyMiddleware(...middlewares))
  );

  // Hot reloading in development
  if ((module as HotNodeModule).hot) {
    (module as HotNodeModule).hot.accept('../App.tsx', () => {
      store.replaceReducer(createRootReducer(history));
    });
  }

  sagaMiddleware.run(rootSaga);
  return store;
}

@Larsrdev might I ask, why have production builds use unpkg and not use Webpack to create a single bundle which has react, react-redux and all such libraries bundled in a properly tree-shaken bundle? We used to use unpkg ourselves and specified in Webpack to make React and such external but it was extremely unreliable as we did not directly control package versions.

royipressburger commented 5 years ago

I had the same issue:

    "connected-react-router": "6.5.2",
    "react-redux": "7.1.0",
    "react-router": "5.0.1",
    "react-router-dom": "5.0.1",

No idea why but removing the package-lock.json and the /node_modules folder and reinstall solved the issue.

favna commented 5 years ago

No idea why but removing the package-lock.json and the /node_modules folder and reinstall solved the issue.

That would be because package-lock locks version installs to whatever it has specified. In this case that's react-redux v6 which you had previously. Read up on what the package lock does here. You should upgrade packages not by just changing your package.json but instead use the npm update command

(or switch to Yarn which uses a more sensible way of a lockfile)

Larsrdev commented 5 years ago

[...] why have production builds use unpkg and not use Webpack to create a single bundle which has react, react-redux and all such libraries bundled in a properly tree-shaken bundle? We used to use unpkg ourselves and specified in Webpack to make React and such external but it was extremely unreliable as we did not directly control package versions.

To reduce the size of our app. We made a gulp script, that is generating the unpkg urls with the fixed version numbers of our package.json. The problem at your package.json @Favna is, that your versions are not fixed ones. You defined the "min" version, but the used one can be another.

I have deleted my package-lock.json and /node-modules dir, and run npm install again, but this does not solve the issue.

This also doesnt work:

<Provider store={store} context={ReactReduxContext}>
            <ConnectedRouter history={history} context={ReactReduxContext}>
                <Route render={() => <div>{'hello'}</div>}/>
            </ConnectedRouter>
</Provider>

This is my package.json on the not working branch:

"dependencies": {
    "@babel/polyfill": "7.4.4",
    "@cospired/i18n-iso-languages": "1.0.2",
    "aws-amplify": "1.1.7",
    "bowser": "2.4.0",
    "connected-react-router": "6.5.0",
    "cropperjs": "1.4.1",
    "draft-js": "0.10.5",
    "dragula": "3.7.2",
    "js-sha1": "0.6.0",
    "lodash": "4.17.11",
    "loglevel": "1.6.1",
    "moment": "2.24.0",
    "qs": "6.5.2",
    "react": "16.8.6",
    "react-dates": "20.2.5",
    "react-dom": "16.8.6",
    "react-ga": "2.5.3",
    "react-localization": "1.0.11",
    "react-markdown": "4.1.0",
    "react-redux": "7.1.0",
    "react-router": "5.0.1",
    "react-router-dom": "5.0.1",
    "react-visibility-sensor": "5.0.2",
    "redux-logger": "3.0.6",
    "scroll-into-view": "1.9.4",
    "semantic-ui-react": "0.82.5",
    "ts-md5": "1.2.4",
    "whatwg-fetch": "3.0.0"
  },
  "scripts": {
    our scripts
  },
  "devDependencies": {
    "@types/amazon-cognito-auth-js": "1.2.0",
    "@types/cropperjs": "1.1.3",
    "@types/draft-js": "0.10.27",
    "@types/dragula": "2.1.34",
    "@types/graphql": "14.2.0",
    "@types/jest": "24.0.12",
    "@types/lodash": "4.14.116",
    "@types/loglevel": "1.5.3",
    "@types/node": "12.0.0",
    "@types/qs": "6.5.1",
    "@types/react": "16.8.15",
    "@types/react-dates": "17.1.5",
    "@types/react-dom": "16.8.4",
    "@types/react-redux": "7.0.1",
    "@types/react-router": "5.0.3",
    "@types/react-router-dom": "4.3.4",
    "@types/redux-logger": "3.0.6",
    "@types/scroll-into-view": "1.6.6",
    "@types/zen-observable": "0.8.0",
    "full-icu": "1.2.1",
    "jest": "24.8.0",
    "jest-junit": "6.4.0",
    "preprocess": "file:./preprocess",
    "redux-devtools-extension": "2.13.8",
    "ts-jest": "24.0.2",
    "ts-mockito": "2.3.1",
    "tslint": "5.16.0",
    "tslint-ban-snippets": "2.1.0",
    "tslint-react": "4.0.0",
    "typescript": "3.4.5"
  },
IAMSBLOL commented 5 years ago

@Favna thank you ,i solve the bug.it is saved my time.

benoitvallon commented 5 years ago

I managed to fix it by doing the following. Furthermore to upgrade to:

"connected-react-router": "6.5.2",
"react-redux": "7.1.0",
"react-router": "5.0.1",
"react-router-dom": "5.0.1",
"redux": "4.0.4",
"redux-saga": "1.0.2"

I had to upgrade any packages using react-router like:

"react-router-ga": "^1.2.1",
"react-router-hash-link": "^1.2.2",
dider7 commented 5 years ago

I've had the same issue yesterday. And this worked for me. Yes, slap me in the face! https://stackoverflow.com/a/55861889/309699

Z-HNAN commented 5 years ago

try this one,

    "connected-react-router": "5",
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-redux": "^5.0.7",
    "react-router": "^4.2.2",
    "react-router-dom": "^4.2.2",
    "redux": "^4.0.1",
    "redux-logger": "^3.0.6",
    "redux-saga": "^1.0.5"
juja0 commented 4 years ago

In my case, this was happening because there were two different versions of "react-router", meaning this is probably not an issue with "connected-react-router". react-router has a variable 'context' and since there was more than one react-router, there were multiple instances of Context floating around and the wrong one was being picked up in a specific scenario causing the exact error mentioned in the OP.

I changed the versions of react-router (and react-router-dom for good measure) to all be the same and it still didn't fix the issue because eventhough the versions were same, there still were multiple copies of the the same version of react-router.

I ran 'npm dedupe' after this and it removed one of the versions and the problem got fixed.

johnpangalos commented 4 years ago

I was able to fix it by passing the react-redux context into the connected react router like this:

<Provider store={store} context={ReactReduxContext}>
  <ConnectedRouter history={history} context={ReactReduxContext}>
    {/* your routes here /*}
  </ConnectedRouter>
</Provider>

Not sure why...

RyanPWalker commented 4 years ago

@Favna Thaaank you! All I was missing was the ReactReduxContext

import { Provider, ReactReduxContext } from 'react-redux';

render(
    <Provider store={store}>
        <ConnectedRouter history={history} context={ReactReduxContext}>
            <App />
        </ConnectedRouter>
    </Provider>,
    document.getElementById('root')
);
yang-jandro commented 4 years ago

In my case, this was happening because there were two different versions of "react-router", meaning this is probably not an issue with "connected-react-router". react-router has a variable 'context' and since there was more than one react-router, there were multiple instances of Context floating around and the wrong one was being picked up in a specific scenario causing the exact error mentioned in the OP.

I changed the versions of react-router (and react-router-dom for good measure) to all be the same and it still didn't fix the issue because eventhough the versions were same, there still were multiple copies of the the same version of react-router.

I ran 'npm dedupe' after this and it removed one of the versions and the problem got fixed.

Had the same issue and this fixed it for me the cleanest. Wasn't aware of npm dedupe, will come in handy in the future.

Note, you also don't need react-router as a dependency, since react-router-dom already has react-router as a dependency and will re-export all it's functionality.

Nodirbek-Sharipov commented 3 years ago

Same happened to me, it was that context api which was causing a conflict. I also had to check every single inner components inside render method to make sure that none of them use context api and has no this.context available inside them. I then deleted context api stuff and wrote an alternative react-redux state, no context api, no problem