skip to Main Content

My React App was working perfectly, but after upgrading to React 18, MUI v5 and Redux v5 it is not rendering anything.

In the terminal I’m getting: "webpack compiled successfully"

But in the Chrome console, I’m getting:

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
printWarning @ react.development.js:209
error @ react.development.js:183
resolveDispatcher @ react.development.js:1592
useContext @ react.development.js:1602
useReduxContext2 @ useReduxContext.ts:14
useSelector2 @ useSelector.ts:175
NoLogin @ auth.js:23
./src/routes/index.js @ index.js:9
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:22
fn @ hot module replacement:61
./src/routes/Routes.js @ index.js:13
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:22
fn @ hot module replacement:61
./src/App.js @ bundle.js:25
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:22
fn @ hot module replacement:61
./src/index.js @ Sidebar.js:420
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:22
(anonymous) @ startup:7
(anonymous) @ startup:7
Show 6 more frames
Show less
react.development.js:1618 

Uncaught TypeError: Cannot read properties of null (reading 'useContext')
    at Object.useContext (react.development.js:1618:1)
    at useReduxContext2 (useReduxContext.ts:14:1)
    at useSelector2 (useSelector.ts:175:1)
    at NoLogin (auth.js:23:1)
    at ./src/routes/index.js (index.js:9:1)
    at options.factory (react refresh:6:1)
    at __webpack_require__ (bootstrap:22:1)
    at fn (hot module replacement:61:1)
    at ./src/routes/Routes.js (index.js:13:1)
    at options.factory (react refresh:6:1)`

This is my package.json:

{
  "name": ********************,
  "version": "0.0.1",
  "private": true,
  "homepage": ********************
  "scripts": {
    "start": ********************
    "start:local": ********************
    "start:sg": ********************
    "build:dev": ********************
    "build": *********************
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 10",
    "not op_mini all"
  ],
  "peerDependencies": {
    "react": "^17.0.0 || ^18.0.0",
    "react-dom": "^17.0.0 || ^18.0.0"
  },
  "dependencies": {
    "@date-io/date-fns": "^3.0.0",
    "@emotion/react": "^11.11.4",
    "@emotion/styled": "^11.11.5",
    "@iconify/react": "^4.1.1",
    "@mui/lab": "^5.0.0-alpha.170",
    "@mui/material": "^5.15.15",
    "@mui/styled-engine": "^5.15.14",
    "@mui/x-date-pickers": "^7.2.0",
    "@reduxjs/toolkit": "^2.2.3",
    "axios": "^1.6.8",
    "chart.js": "^4.4.2",
    "clsx": "^2.1.0",
    "date-fns": "^3.6.0",
    "env-cmd": "^10.1.0",
    "i18n-iso-countries": "^7.10.0",
    "immer": "^10.0.3",
    "material-ui-confirm": "^3.0.12",
    "moment": "^2.30.1",
    "mui-datatables": "^4.3.0",
    "notistack": "^3.0.1",
    "numeral": "^2.0.6",
    "polished": "^4.1.3",
    "prop-types": "^15.7.2",
    "react": "^17.0.0 || ^18.0.0",
    "react-app-polyfill": "^3.0.0",
    "react-dom": "^17.0.0 || ^18.0.0",
    "react-feather": "^2.0.10",
    "react-perfect-scrollbar": "^1.5.8",
    "react-redux": "^9.1.1",
    "react-router-dom": "^6.22.3",
    "react-scripts": "^5.0.1",
    "react-select": "^5.2.0",
    "redux": "^5.0.1",
    "redux-auth-wrapper": "^3.0.0",
    "redux-saga": "^1.1.3",
    "reselect": "^5.1.0",
    "styled-components": "^6.1.8",
    "url": "^0.11.3"
  },
  "devDependencies": {
    "@babel/plugin-proposal-private-property-in-object": "^7.21.11"
  }
}

This is my App.js:

import React from "react";
import { connect } from "react-redux";
import { BrowserRouter as Router } from "react-router-dom";
import { ThemeProvider, StyledEngineProvider } from "@mui/material/styles";
import AdapterDateFns from '@mui/lab/AdapterDateFns';
import LocalizationProvider from '@mui/lab/LocalizationProvider';
import { SnackbarProvider } from "notistack";

import maTheme from "./theme";
import Routes from "./routes/Routes";
import { ConfirmProvider } from 'material-ui-confirm';

const App = ({ theme }) => {
  return (
    <StyledEngineProvider injectFirst>
      <ThemeProvider theme={maTheme[theme.currentTheme]}>
        <LocalizationProvider dateAdapter={AdapterDateFns}>
          <ConfirmProvider>
            <SnackbarProvider maxSnack={1}>
              <Routes />
            </SnackbarProvider>
          </ConfirmProvider>
        </LocalizationProvider>
      </ThemeProvider>
    </StyledEngineProvider>
  );
};

const ConnectedApp = connect(store => ({ theme: store.themeReducer }))(App);

function AppWithRouter() {
  return (
    <Router>
      <ConnectedApp/>
    </Router>
  );
}

export default AppWithRouter;`

This is my index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store/index';

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <Provider store={store}>
      <App tab="home"/>
    </Provider>
  </React.StrictMode>
);

This is my Routes/index.js:

import React from "react";

import async from "../components/Async";

import { Truck } from "react-feather";
import {NeedsLogin, NoLogin} from "./auth";

// Auth components
const SignIn = NoLogin(() => import("../pages/auth/SignIn"));
const SignUp = async(() => import("../pages/auth/SignUp"));
const ForgotPassword = async(() => import("../pages/auth/ForgotPassword"));
const ResetPassword = async(() => import("../pages/auth/ResetPassword"));
const Page404 = async(() => import("../pages/auth/Page404"));
const Page500 = async(() => import("../pages/auth/Page500"));

// Pages components
const OnBoard = NeedsLogin(() => import("../pages/pages/OnBoard"));
const Institutions = NeedsLogin(() => import("../pages/pages/Institutions/Institutions"));
const LoginInstitutions = NeedsLogin(() => import("../pages/pages/Institutions/LoginInstitution"));
const Instances = NeedsLogin(() => import("../pages/pages/Instances/Instances"));
const EditInstance = NeedsLogin(() => import("../pages/pages/Instances/editInstance"));


//Account Routes
const MyAccount = NeedsLogin(() => import("../pages/pages/Account/MyAccount"));

const homeRoutes = {
  id: "Home",
  path: "/",
  component: OnBoard,
  children: null,
  hidden: true
};

const accountRoutes = {
  id: "My Account",
  path: "/my_account",
  component: MyAccount,
  children: null,
  hidden: true
};

const institutionsRoutes = {
  id: "Institutions",
  path: "/institutions",
  component: Institutions,
  children: null,
  hidden: true
};

const loginInstitutionsRoutes = {
  id: "Distribution Institutions",
  path: "/login_institutions",
  component: LoginInstitutions,
  icon: <Truck />,
  children: null,
};

const instancesRoutes = {
  id: "Instances",
  path: "/instances",
  component: Instances,
  children: null,
  hidden: true
};

const editInstanceRoutes = {
  id: "Edit Instance",
  path: "/editInstance",
  component: EditInstance,
  children: null,
  hidden: true
};

const authRoutes = {
  id: "Auth",
  path: "/auth",
  hidden: true,
  children: [
    {
      path: "/auth/sign-in",
      name: "Sign In",
      component: SignIn
    },
    {
      path: "/auth/sign-up",
      name: "Sign Up",
      component: SignUp
    },
    {
      path: "/auth/forgot-password",
      name: "Forgot Password",
      component: ForgotPassword
    },
    {
      path: "/reset_your_password/:id",
      name: "Reset Password",
      component: ResetPassword
    },
    {
      path: "/auth/404",
      name: "404 Page",
      component: Page404
    },
    {
      path: "/auth/500",
      name: "500 Page",
      component: Page500
    }
  ]
};

export const dashboard = [
  homeRoutes,
  accountRoutes,
  institutionsRoutes,
  instancesRoutes,
  editInstanceRoutes,
  loginInstitutionsRoutes
];

export const auth = [authRoutes];

export default [
  homeRoutes,
  accountRoutes,
  authRoutes,
  institutionsRoutes,
  instancesRoutes,
  editInstanceRoutes,
  loginInstitutionsRoutes
];

This my auth.js:

import { useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import Loader from '../components/Loader';

const NeedsLogin = ({ children }) => {
  const signedIn = useSelector(state => state.auth.signedIn);
  const loading = useSelector(state => state.auth.loading);
  const history = useNavigate();

  if (loading) {
    return <Loader />;
  }

  if (!signedIn) {
    history('/auth/sign-in');
    return null;
  }

  return children;
};

const NoLogin = ({ children }) => {
  const signedIn = useSelector(state => state.auth.signedIn);
  const loading = useSelector(state => state.auth.loading);
  const history = useNavigate();

  if (loading) {
    return <Loader />;
  }

  if (signedIn) {
    history('/');
    return null;
  }

  return children;
};

export { NeedsLogin, NoLogin };

I tried deleting the React.StrictMode and got the same result.

I checked react and react-dom versions in my project with:

npm ls react-dom

├─┬ @mui/[email protected]
│ ├─┬ @mui/[email protected]
│ │ ├─┬ @floating-ui/[email protected]
│ │ │ └── [email protected] deduped
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ ├── [email protected] deduped
│ └─┬ [email protected]
│   └── [email protected] deduped
├─┬ @mui/[email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ ├── [email protected] deduped
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected] deduped
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │   └── [email protected] deduped
│ └─┬ [email protected]
│   └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├── [email protected]
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
└─┬ [email protected]
  └── [email protected] deduped

npm ls react

├─┬ @emotion/[email protected]
│ ├─┬ @emotion/[email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ @emotion/[email protected]
│ └── [email protected] deduped
├─┬ @iconify/[email protected]
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ ├─┬ @mui/[email protected]
│ │ ├─┬ @floating-ui/[email protected]
│ │ │ └── [email protected] deduped
│ │ └── [email protected] deduped
│ ├─┬ @mui/[email protected]
│ │ ├─┬ @mui/[email protected]
│ │ │ └── [email protected] deduped
│ │ └── [email protected] deduped
│ ├─┬ @mui/[email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ └── [email protected] deduped
├─┬ @reduxjs/[email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ ├─┬ @mui/[email protected]
│ │ └── [email protected] deduped
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected] deduped
│ │ ├─┬ [email protected]
│ │ │ └── [email protected] deduped
│ │ ├─┬ [email protected]
│ │ │ └── [email protected] deduped
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ ├── [email protected] deduped
│ └─┬ [email protected]
│   └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ ├── [email protected] deduped
│ └─┬ [email protected]
│   └── [email protected] deduped
├─┬ [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ ├── [email protected] deduped
│ └─┬ [email protected]
│   └── [email protected] deduped
├── [email protected]
└─┬ [email protected]
  └── [email protected] deduped

I tried uninstalling mui-datatables but it is still the same.

2

Answers


  1. Try using a single version of react and react-dom in your package.json file (like in the snippet mentioned above), un-install your node modules folder and do a fresh npm install.

    {
      "dependencies": {
        "react": "^18.0.0",
        "react-dom": "^18.0.0"
      }
    }
    
    Login or Signup to reply.
  2. The issue may be with the dependency: react-sortable-tree-patch-react-17 which is pulling in v17 of react and react-dom.

    ...
    ├─┬ [email protected]
    │ ├─┬ @mui/[email protected]
    │ │ └── [email protected] deduped
    │ ├─┬ [email protected]
    │ │ └── [email protected] deduped
    │ ├─┬ [email protected]
    │ │ ├─┬ [email protected]
    │ │ │ └── [email protected] deduped
    │ │ ├─┬ [email protected]
    │ │ │ └── [email protected] deduped
    ...
    

    Looking at the dependent package mui-datatables this may still be an issue.

    If you are using a relatively new version of npm, you could add overrides to force the same version of react and react-dom to 18.2.0. Or if yarn is an option, you can add similar config resolutions.

    In your package.json add the following, then cleanly install your dependencies by deleting ./node_modules and package-lock.json before running npm i.

    {
    ...
      "overrides": {
        "react": "18.2.0",
        "react-dom": "18.2.0"
      }
    }
    

    However this could have side effects in the library still expecting react v17.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search