Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hooks + multiple instances of React #13991

Open
brunolemos opened this issue Oct 27, 2018 · 494 comments
Open

Hooks + multiple instances of React #13991

brunolemos opened this issue Oct 27, 2018 · 494 comments

Comments

@brunolemos
Copy link

brunolemos commented Oct 27, 2018

To people coming from search: please read this page first. It contains most common possible fixes!

Do you want to request a feature or report a bug?

Enhancement

What is the current behavior?

I had multiple instances of React by mistake.

When trying to use hooks, got this error:
hooks can only be called inside the body of a function component

Which is not correct since I was using function components. Took me a while to find the real cause of the issue.

What is the expected behavior?

Show the correct error message. Maybe detect that the app has multiple instances of React and say that it may be the reason of bugs.

@brunolemos brunolemos changed the title Wrong hooks error message when app has multiple instances of React Hooks + multiple instances of React Oct 27, 2018
@philipp-spiess
Copy link
Contributor

So just for clarification: You were importing a hook (say useState) from a different react module than the one used to render the component?

I agree that this is confusing. I'm not sure though if we have a way of knowing if any other React module is rendering. AFAIK we try to run React in isolation as much as possible so that multiple React instances can work in the same global context without issues.

Otherwise we could probably update the error message and mention this case as well if it's not too confusing.

@brunolemos
Copy link
Author

brunolemos commented Oct 27, 2018

Yes, I compared React1 === React2 and it was false (React1 being from index.js and React2 being from the file using the hook). When this happens, hooks fail with the generic error message above.

This issue is to raise awareness of this case and maybe improve the error message in some way to help people that face this. It's probably very edge though.

@GabrielBB
Copy link

GabrielBB commented Nov 1, 2018

Yup, i tried to npm link a package i'm creating. It throws that same error since the other package is also using hooks but with its own React. I had to publish my package to NPM and then import it directly from NPM. That way the error was gone, but i hope this is fixed since publishing a package without testing it is bad, obviously

@mpeyper
Copy link

mpeyper commented Nov 2, 2018

Lerna monorepos suffer from this as well when a custom hook is defined in one package and used by another as the symlinked dependencies use their own copy of react.

I have a (hacky) workaround at the moment using npm-link-shared and a prestart npm script to essentially replace the one package's react dependency with a symlink to the other's, so they use the same instance.

"prestart": "npm-link-shared ./node_modules/<other package>/node_modules . react"

@apieceofbart
Copy link

I had the same issue and I resolved it by adding:

 alias: {
        react: path.resolve('./node_modules/react')
      }

to resolve property in webpack config of my main app.

It's was obviously my mistake of using two copies of React but I agree that it would be great if the error message was better. I think this is maybe similar to: #2402

@GabrielBB
Copy link

@mpeyper It works. Thanks

@jimbo
Copy link

jimbo commented Nov 18, 2018

@apieceofbart That worked for me. Thanks for the suggestion. 👍

@jbandi
Copy link

jbandi commented Dec 3, 2018

As I understand this problem arises when there are multiple copies of React in the same bundle.

Is this also a problem if two separate bundles with their own copies of React are bootstrapping their own React applications on separate dom elements, like described here: https://medium.jonasbandi.net/hosting-multiple-react-applications-on-the-same-document-c887df1a1fcd

I think the latter is a common "integration" pattern used for instance in the single-spa meta-framework (https://github.com/CanopyTax/single-spa).

@vpicone
Copy link

vpicone commented Dec 10, 2018

I'm also having this issue even with the exact same react versions, developing hooks to be published on their own is broken when using npm-link. Getting the same unhelpful hooks can only be called inside the body of a function component message. @apieceofbart's alias solution solved this for me. Thanks so much!

@dotlouis
Copy link

Same issue here when I npm link a package to my main application. I could not get babel-plugin-module-resolver working.
It says:
Could not find module './node_module/react'
This is annoying because it prevents me from testing my component locally before publishing it.

@doasync
Copy link

doasync commented Dec 22, 2018

I fixed my issue by removing the caret in "react": "^16.7.0-alpha.2"
Here is the full comment: #14454 (comment)

@pelotom
Copy link

pelotom commented Dec 22, 2018

I'm using Yarn, and fixed this by forcing resolution in my package.json:

  "resolutions": {
    "**/react": "16.7.0-alpha.2",
    "**/react-dom": "16.7.0-alpha.2"
  },

@leecade
Copy link

leecade commented Dec 24, 2018

Same here!!

@zbuttram
Copy link

zbuttram commented Feb 5, 2019

Just wanted to leave a note here for anyone who might have had this problem in the same manner I did.

We're running React and Rails with the react-rails gem and rendering components directly into Rails views. I was receiving this error every time a new version of the app was pushed, because Turbolinks was grabbing the new JS bundle out of the <head> which loaded up an extra instance of React. Solution was to have Turbolinks do a full page reload when it detects the bundle has changed: https://github.com/turbolinks/turbolinks#reloading-when-assets-change

This appears to have solved it for us.

@taylorham
Copy link

taylorham commented Feb 6, 2019

I'm very excited to finally put Hooks into production, and we all owe a huge thank you to everyone who made it possible. They're a ton of fun to work with and have made my code shorter and more declarative.

Just as a heads up, this issue is still relevant in the released version with the same unhelpful error message of "Hooks can only be called inside the body of a function component."

Is this something that can be fixed? I imagine it might become more and more prevalent as more devs start to implement the new features, and a clearer error message would go a long way in lieu of an outright "fix".

Thanks again for all the hard work and congrats on the release! It's really an amazing set of features.

Edit: Should have looked closer at the open PRs, just found #14690 that addresses this. Thanks @threepointone!

@dotlouis
Copy link

dotlouis commented Feb 7, 2019

@taylorham The link in the commit doesn't point to anything yet. I'll wait for it, but this is an issue I have been having since using hooks in a linked (as of npm link) package and it's impossible to work with it locally without publishing.
After looking severals issues, I tought this was an issue with react-hot-loader that was compiling components to classes, but even after they released a version with Hook support, it still fails the same way.
I've tried a lot of different hacks but no luck. I don't know why everybody hasn't been struck with this issue yet 🧐

@adeleke5140
Copy link

I faced this issue in Gatsby 5 and the problem was because I violated the rule of hooks. I did not call it inside a React functional component which caused the error.

@DoReVo
Copy link

DoReVo commented May 18, 2023

If you're facing this issue and you're:

  1. Using vite as your development server
  2. Also using cloudflare tunnel to serve your development server on a domain such as https://example.com.

And you seems to only have this issue when going to the app at example.com, but the app is okay when going to localhost:5173, then do the following on example.com,

  1. Open up the dev tool
  2. Go to network tab
  3. Tick disable cache
  4. Full reload example.com by pressing F5.

This fixed the issue for me cause the browser is caching stuff on example.com, but not on localhost:5173.

@fepimentel
Copy link

I have this same issue

@04756
Copy link

04756 commented Jun 19, 2023

I have this issue too and already spend almost whole day to solve it.
I try to follow the official guidance to find the reason, but nothing help.
I print the react version, it prints false, but React1(index.js) is undefined. Hope someone can give me some help, thanks very much!

ps: I have to complain that i have no idea why it appear. My project work in React 16.14.x. sad.

@04756
Copy link

04756 commented Jun 19, 2023

I have this issue too and already spend almost whole day to solve it. I try to follow the official guidance to find the reason, but nothing help. I print the react version, it prints false, but React1(index.js) is undefined. Hope someone can give me some help, thanks very much!

ps: I have to complain that i have no idea why it appear. My project work in React 16.14.x. sad.

THANK GOD! I solve my problem in the last minutes of today.
My issue:
Work nice in development, but can not work in product env. And the console gets Minified React error#321 .
I solve my issue by three steps(can't miss one of them in my case):

  1. add alias like apieceofbart
  2. register global React in webpack plugin(I have to do this, or it will throw error "React is undefined")
new webpack.ProvidePlugin({
            React: 'react',
        }),
  1. upgrade all dependencies.(I suppose there are some dependencies need upgrade or it will cause some unexpected actions when deploy project)
    pnpm upgrade
    :)

@mchepuri
Copy link

mchepuri commented Jul 18, 2023

Hi,
I came across a scenario which is neither found in https://legacy.reactjs.org/warnings/invalid-hook-call-warning.html nor here in this thread
I have documented my use case here. https://medium.com/@murali.chepuri/invalid-hook-call-error-another-cause-5fb59710c269
And here is the code that is causing this. https://github.com/mchepuri/InvalidHookCall/tree/main
Github README has all the steps how to reproduce. Wondering if the the way how we import the components could also cause the issue?
Wondering if this is a bug?

@adeleke5140
Copy link

adeleke5140 commented Jul 19, 2023

Hi,

I came across a scenario which is neither found in https://legacy.reactjs.org/warnings/invalid-hook-call-warning.html nor here in this thread

I have documented my use case here. https://medium.com/@murali.chepuri/invalid-hook-call-error-another-cause-5fb59710c269

And here is the code that is causing this. https://github.com/mchepuri/InvalidHookCall/tree/main

Github README has all the steps how to reproduce. Wondering if the the way how we import the components could also cause the issue?

Wondering if this is a bug?

I'd take a look at it.

@mchepuri I wasn't able to recreate the bug but what I noticed was that you were mixing up default export and named export

Default exports are in the format:

//export
const Component = () => {}

export default Component

//import
import Component from '@dir'

Named export are in the format:

//export
const Component = () => {}

export { Component }

//import
import { Component } from '@dir'

I got the landing component to work with that.
It is still not working in Safari, weird.

@o-alquimista
Copy link

o-alquimista commented Aug 19, 2023

I got this error by calling

root.render(MyComponent());

instead of

root.render(<MyComponent />)

The component being rendered is using useState, and it is defined in MyComponent.tsx, which is a TypeScript JSX module in a bundler context (webpack). TypeScript jsx option is set to react, so import React from "react" is necessary.

import React, {useState} from "react";

export default function MyComponent() {
    const [myVar, setMyVar] = useState('testing...');

   // ...
}

It's a silly mistake I made, and the resulting error message is very confusing, which made me lose hours trying to fix this.

Related: https://react.dev/reference/react-dom/client/createRoot#im-getting-an-error-functions-are-not-valid-as-a-react-child

@drush
Copy link

drush commented Aug 19, 2023 via email

@J0EKW
Copy link

J0EKW commented Aug 23, 2023

This keeps being flared as an incorrect usage of the 'useState' hook, although it doesn't seem to fall into any of the usual pitfalls to my eyes. I've tried some different strategies for removing duplicate Reacts and there's no mismatch in version. The closest I can think is that the function it's used in is later used as a constant, but I've tried ways of removing the constant with the same results. Again, this might just be a goof.

import React, { useState } from 'react'
import { OptionsType } from '../types'

const Def = {
    animation: true,
}

function Option<T, >(normParam: T): {get: Function, set: Function, reset: Function} {
    const def: T = normParam;
    const [value, setValue] = useState<T>(def);


    const get = (): T => {
        return value
    }

    const set = (newValue: T): void => {
        console.log(newValue)
        setValue(newValue)
    }

    const reset = (): void => {
        setValue(def)
    }

    return {
        get: () => get(),
        set: (value: T) => set(value),
        reset: () => reset(),
    }
}

function Options(): OptionsType {
    const animation = Option<boolean>(Def.animation)

    return {
        animation: animation
    }
}

export default Options()

@snake-py
Copy link

snake-py commented Sep 1, 2023

Hello, I also have this issue. I read through the page carefully and checked everything and could not see anything amiss.

I have a custom component library in React 18.2.0 and a Project in React 18.2.0. Both use Vite for bundling. I am using serve side rendering with vite-plugin-ssr. I also asked the maintainer of VPS, but he said that it is a Dependency Injection issue of react-dom => vikejs/vike#1101

The issue is always occurring if I enable SSR, I don't see it if I only use client side rendering, which makes think that it might be due to that import ReactDOMServer from 'react-dom/server'; is somehow using another React then my library does.

In my library I have created a dummy hook:

function testHook() {
  console.log('testHook: testHook');
  console.log('testHook: React', React);
  console.log('testHook: ReactDOM', ReactDOM);
  console.log('testHook: testHook');
  const [testBool, setTestBool] = useState(false);
  useEffect(() => {}, []);
}

I am calling this hook in my top level page component:

function Page() {
  //@ts-ignore
  ReactDOM.testNew = 'testNew'; // I can see that this appended in my lib
  //@ts-ignore
  React.test = 'test';  // I can see that this appended in my lib
  const test = testHook();
  return <></>;
}

I also checked if react-dom is using the same React

./node_modules/react-dom/index.js

if (typeof window !== 'undefined') {
  window.React1 = require('react');
}

./page/dummy.tsx
import React from 'react';
import ReactDOM from 'react-dom';
...

  if (typeof window === 'undefined') {
    return <></>;
  }
  @ts-ignore
  window.React2 = require('react');
  @ts-ignore
  console.log(window.React1 === React); // true

So It seems to me that I am doing everything correctly and still see this issue.

I saw that the issue goes away if I do either:

  1. Use Client Side Rendering (not really an option)
  2. Redefine components and customHooks again in my project (not really an option)

Appendix:

I am unsure if this helps but here are also my Vite bundling configs of my lib:

/// <reference types="vitest" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
import dts from 'vite-plugin-dts';

// https://vitejs.dev/config/
export default defineConfig({
  build: {
    lib: {
      entry: path.resolve(__dirname, 'src/index.ts'),
      formats: ['es', 'cjs'],
      name: '@workdigtital/component-library-react',
      fileName: (format) => `index.${format}.js`
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM'
        },
        exports: 'named'
      }
    }
  },
  plugins: [react(), dts({ insertTypesEntry: true })],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: ['./src/tests/setup.ts'],
    exclude: ['**/node_modules/**', '**/dist/**', '**/coverage/**', '**.stories**', '.storybook/**', '**.types**'],
    coverage: {
      all: true,
      exclude: ['**/*.stories.tsx', '.storybook/**'],
      provider: 'c8',
      reporter: ['cobertura', 'html']
    }
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@flaticon': path.resolve(__dirname, './node_modules/@flaticon')
    }
  }
});

Stack Trace:

react-dom.development.js:20662 Uncaught Error: Cannot read properties of null (reading 'useState')
    at updateDehydratedSuspenseComponent (react-dom.development.js:20662:17)
    at updateSuspenseComponent (react-dom.development.js:20362:16)
    at beginWork (react-dom.development.js:21624:14)
    at beginWork$1 (react-dom.development.js:27426:14)
    at performUnitOfWork (react-dom.development.js:26557:12)
    at workLoopSync (react-dom.development.js:26466:5)
    at renderRootSync (react-dom.development.js:26434:7)
    at performConcurrentWorkOnRoot (react-dom.development.js:25738:74)
    at workLoop (scheduler.development.js:266:34)
    at flushWork (scheduler.development.js:239:14)

Solution

My issue was with a third party plugin https://socket.dev/npm/package/vite-plugin-circular-dependency, removing it helped.

@hansede
Copy link

hansede commented Sep 13, 2023

None of the above solutions worked for me until I upgraded styled-components from v5 to v6. I was even getting true from React1 === React2 after using the Webpack alias solution, but was still seeing hundreds of these warnings.

If you're using styled-components, try upgrading.

@AjaykumarX
Copy link

I am getting "Invalid Hook Call" error for below code

export function GetMemoedData(param) {
     const data = useMemo(() => {
           return ['abcd']
     });
return data;
}

I am calling above function via Saga (yield call(GetMemoedData, params);

Any help on this would be appreciated

@danawan0409
Copy link

I'm getting Invalid hook call. I'm using this code from email.js:

`const Contact = () => {
const form = useRef;

const sendEmail = (e) => {
    e.preventDefault();
    
    emailjs.sendForm('YOUR_SERVICE_ID', 'YOUR_TEMPLATE_ID', form.current, 'YOUR_PUBLIC_KEY')
    .then((result) => {
        console.log(result.text);
    }, (error) => {
        console.log(error.text);
    });
};`

I'd appreciate the help

@jomefavourite
Copy link

😪😔

@tuseefahmed786
Copy link

I am creating a UI library so I used useState in my library component and when I use this library in my project with npm link library or npm install library I get this error

`reactjscomponents.js:2 Uncaught TypeError: Cannot read properties of null (reading 'useState')

` at t.useState (reactjscomponents.js:2:1)
at o (reactjscomponents.js:2:1)
at renderWithHooks (react-dom.development.js:16305:1)
at mountIndeterminateComponent (react-dom.development.js:20074:1)
at beginWork (react-dom.development.js:21587:1)
at beginWork$1 (react-dom.development.js:27426:1)
at performUnitOfWork (react-dom.development.js:26557:1)
at workLoopSync (react-dom.development.js:26466:1)
at renderRootSync (react-dom.development.js:26434:1)
at recoverFromConcurrentError (react-dom.development.js:25850:1)

my package.json
{ "name": "@tuseefahmed110/al-kafeel-ui", "version": "1.0.4", "description": "we'r creating Pixel-Perfect UI Components library", "main": "dist/reactjscomponents.js", "scripts": { "build": "webpack", "test": "jest" }, "jest": { "setupFilesAfterEnv": [ "@testing-library/jest-dom/extend-expect" ] }, "keywords": [ "reactjs" ], "author": "Tuseef A. By AL-Kafeel Agency ", "license": "ISC", "dependencies": { "babel-plugin-transform-import-css": "^1.0.0-alpha.11", "react-dom": "file:../common/node_modules/react-dom", "react": "file:../common/node_modules/react" }, "devDependencies": { "@babel/cli": "^7.23.0", "@babel/core": "^7.23.2", "@babel/preset-env": "^7.23.2", "@babel/preset-react": "^7.22.15", "@testing-library/jest-dom": "^6.1.4", "@testing-library/react": "^14.0.0", "babel-cli": "^6.26.0", "babel-loader": "^9.1.3", "chai": "^4.3.10", "css-loader": "^6.8.1", "jest": "^29.7.0", "mocha": "^10.2.0", "style-loader": "^3.3.3", "webpack": "^5.89.0", "webpack-cli": "^5.1.4", "sass": "^1.54.9", "sass-loader": "^13.0.2", "webpack-dev-server": "^4.11.0" } }

my webpack file
`const path = require("path");
const webpack = require("webpack");

module.exports = {
entry: "./src/index.js",
mode: "development",
module: {
rules: [
{
test: /.(js|jsx|ts|tsx)$/,
loader: "babel-loader",
options: { presets: ["@babel/env"] }
},
{
test: /.(scss|css)$/,
use: ["style-loader", "css-loader", "sass-loader"]
}
]
},
resolve: { extensions: ["*", ".js", ".jsx", ".tsx", ".ts"],
alias: {
react: path.resolve(path.join(__dirname, './node_modules/react')),
'react-dom': path.resolve(path.join(__dirname, './node_modules/react-dom'))
} },
output: {
path: path.resolve(__dirname, "dist/"),
publicPath: "/dist/",
filename: "bundle.js"
},
externals: {
react: 'react',
'react-dom': 'react-dom'
},
devServer: {
allowedHosts: 'all',
open: true,
static: {
directory: path.join(__dirname, "public/"),
staticOptions: {},
publicPath: '/',
serveIndex: true,
watch: true,
},
compress: true,
historyApiFallback: true,
host: 'localhost',
port: 6600,
hot: true,
},
plugins: [new webpack.HotModuleReplacementPlugin()]
};`

my babel file
{ "presets": ["@babel/preset-env", "@babel/preset-react"] }

@mygithub07
Copy link

mygithub07 commented Nov 17, 2023

I am also getting Invalid hook call. Hooks can only be.. error . I started getting this when I changed my whole solution to use react-router-dom and introduced routing. Currently , on server, my app is working fine which does not have react-router-dom yet and has the same hooks logic as my local.

So I am guessing , it might have to do something with 1. mismatching versions of React and React DOM. or 2.more than one copy of React

. In general , react-router-dom and its compatibility with react . But at this point I am unbale to figure out
How can I resolve this error , please? when I run npm ls react-dom , I get

├─┬ @wordpress/scripts@26.6.0
│ ├─┬ @wordpress/babel-preset-default@7.20.0
│ │ └─┬ @wordpress/element@5.13.0
│ │   └── react-dom@18.2.0 deduped
│ └── react-dom@18.2.0
├─┬ rc-slider@10.3.1
│ ├─┬ rc-util@5.38.0
│ │ └── react-dom@18.2.0 deduped
│ └── react-dom@18.2.0 deduped
└─┬ react-router-dom@6.17.0
  └── react-dom@18.2.0 deduped

I am getting true for this check - window.React1 === window.React2 check

any help is appreciated

@AndreyEscobar
Copy link

do i have duplicate react?

projetofirestore@1.0.0 C:\APP\ProjetoFirestore
+-- @react-native-firebase/app@18.3.0
| -- react@18.2.0 deduped +-- @react-native-picker/picker@2.5.1 | -- react@18.2.0 deduped
+-- @react-navigation/drawer@6.6.4
| +-- @react-navigation/elements@1.3.19
| | -- react@18.2.0 deduped | +-- @react-navigation/native@6.1.7 | | +-- @react-navigation/core@6.4.9 | | | -- react@18.2.0 deduped
| | -- react@18.2.0 deduped | -- react@18.2.0 deduped
+-- @react-navigation/native-stack@6.9.13
| -- react@18.2.0 deduped +-- expo-camera@13.4.3 | -- @koale/useworker@4.0.2
| -- react@16.14.0 +-- expo-router@2.0.6 | +-- @radix-ui/react-slot@1.0.1 | | +-- @radix-ui/react-compose-refs@1.0.0 | | | -- react@18.2.0 deduped
| | -- react@18.2.0 deduped | +-- @react-navigation/bottom-tabs@6.5.8 | | -- react@18.2.0 deduped
| +-- expo-head@0.0.12
| | -- react@18.2.0 deduped | -- react-helmet-async@1.3.0
| -- react@18.2.0 deduped +-- pullstate@1.25.0 | -- react@18.2.0 deduped
+-- react-native-calendars@1.1302.0
| -- recyclerlistview@4.2.0 | -- react@18.2.0 deduped
+-- react-native-gesture-handler@2.12.1
| -- react@18.2.0 deduped +-- react-native-paper@5.11.1 | +-- @callstack/react-theme-provider@3.0.9 | | -- react@18.2.0 deduped
| +-- react@18.2.0 deduped
| -- use-latest-callback@0.1.6 | -- react@18.2.0 deduped
+-- react-native-reanimated@3.3.0
| -- react@18.2.0 deduped +-- react-native-safe-area-context@4.6.3 | -- react@18.2.0 deduped
+-- react-native-screens@3.22.1
| +-- react-freeze@1.0.3
| | -- react@18.2.0 deduped | -- react@18.2.0 deduped
+-- react-native-web@0.19.9
| +-- react-dom@18.2.0
| | -- react@18.2.0 deduped | -- react@18.2.0 deduped
+-- react-native@0.72.3
| +-- react-shallow-renderer@16.15.0
| | -- react@18.2.0 deduped | +-- react@18.2.0 deduped | -- use-sync-external-store@1.2.0
| -- react@18.2.0 deduped -- react@18.2.0

@mygithub07
Copy link

I am also getting Invalid hook call. Hooks can only be.. error . I started getting this when I changed my whole solution to use react-router-dom and introduced routing. Currently , on server, my app is working fine which does not have react-router-dom yet and has the same hooks logic as my local.

So I am guessing , it might have to do something with 1. mismatching versions of React and React DOM. or 2.more than one copy of React

. In general , react-router-dom and its compatibility with react . But at this point I am unbale to figure out How can I resolve this error , please? when I run npm ls react-dom , I get

├─┬ @wordpress/scripts@26.6.0
│ ├─┬ @wordpress/babel-preset-default@7.20.0
│ │ └─┬ @wordpress/element@5.13.0
│ │   └── react-dom@18.2.0 deduped
│ └── react-dom@18.2.0
├─┬ rc-slider@10.3.1
│ ├─┬ rc-util@5.38.0
│ │ └── react-dom@18.2.0 deduped
│ └── react-dom@18.2.0 deduped
└─┬ react-router-dom@6.17.0
  └── react-dom@18.2.0 deduped

I am getting true for this check - window.React1 === window.React2 check

any help is appreciated

This is resolved. The issue here was that I was using two ReactDOM.render in my solution one in index.js and other one in a component named RenderTopMenuResultPage , which I used only to render a different component. So it was creating two react trees somehow. I changed

export const RenderTopMenuResultPage = (props) => {

    ReactDOM.render(    
        <CreateTopMenuResultPage />, 
        document.getElementById('result-page-sort-menu')
    )
} 

to


export const RenderTopMenuResultPage = (props) => {
    return <CreateTopMenuResultPage />;
};

So the issue was never one of these which I was thinking - hooks rules , mismatching versions of React and React DOM , more than one copy of React Or using useNavigate() . They may be an issue in some scenarios but in this particular scenario the issue was using two ReactDOM.render

@craigkovatch
Copy link

craigkovatch commented Nov 21, 2023

I hit this error today on a component which renders a sub-component and attaches a callback ref to that sub-component. Inside the handler for that callback ref, it was calling a method which eventually called setState on the host component. This caused it to attempt to setState during an unmounting of the host because the callback ref handler wasn't checking the ref === null case.

Not sure if integral to the repro, but it also relied on accidentally double-rendering our entire dev page on page load. We were accidentally loading the entire webpack bundle twice, so the first render was getting unmounted and blown away by the second render.

It was quite hard to track down and didn't fit the three things listed in the troubleshooting error message. A big part of the difficulty was that the error was being reported from a hooks/function component which was being rendered as a sibling of the aforementioned host component, not a child.

@tuseefahmed786
Copy link

do i have duplicate react?

projetofirestore@1.0.0 C:\APP\ProjetoFirestore +-- @react-native-firebase/app@18.3.0 | -- react@18.2.0 deduped +-- @react-native-picker/picker@2.5.1 | -- react@18.2.0 deduped +-- @react-navigation/drawer@6.6.4 | +-- @react-navigation/elements@1.3.19 | | -- react@18.2.0 deduped | +-- @react-navigation/native@6.1.7 | | +-- @react-navigation/core@6.4.9 | | | -- react@18.2.0 deduped | | -- react@18.2.0 deduped | -- react@18.2.0 deduped +-- @react-navigation/native-stack@6.9.13 | -- react@18.2.0 deduped +-- expo-camera@13.4.3 | -- @koale/useworker@4.0.2 | -- react@16.14.0 +-- expo-router@2.0.6 | +-- @radix-ui/react-slot@1.0.1 | | +-- @radix-ui/react-compose-refs@1.0.0 | | | -- react@18.2.0 deduped | | -- react@18.2.0 deduped | +-- @react-navigation/bottom-tabs@6.5.8 | | -- react@18.2.0 deduped | +-- expo-head@0.0.12 | | -- react@18.2.0 deduped | -- react-helmet-async@1.3.0 | -- react@18.2.0 deduped +-- pullstate@1.25.0 | -- react@18.2.0 deduped +-- react-native-calendars@1.1302.0 | -- recyclerlistview@4.2.0 | -- react@18.2.0 deduped +-- react-native-gesture-handler@2.12.1 | -- react@18.2.0 deduped +-- react-native-paper@5.11.1 | +-- @callstack/react-theme-provider@3.0.9 | | -- react@18.2.0 deduped | +-- react@18.2.0 deduped | -- use-latest-callback@0.1.6 | -- react@18.2.0 deduped +-- react-native-reanimated@3.3.0 | -- react@18.2.0 deduped +-- react-native-safe-area-context@4.6.3 | -- react@18.2.0 deduped +-- react-native-screens@3.22.1 | +-- react-freeze@1.0.3 | | -- react@18.2.0 deduped | -- react@18.2.0 deduped +-- react-native-web@0.19.9 | +-- react-dom@18.2.0 | | -- react@18.2.0 deduped | -- react@18.2.0 deduped +-- react-native@0.72.3 | +-- react-shallow-renderer@16.15.0 | | -- react@18.2.0 deduped | +-- react@18.2.0 deduped | -- use-sync-external-store@1.2.0 | -- react@18.2.0 deduped -- react@18.2.0

I noticed I have duplicate react in my library How can remove ??

@chrisandrewca
Copy link

chrisandrewca commented Dec 22, 2023

Hello, I believe I have part of the solution for this error message. This error message can present itself in multiple ways depending on the exact APIs used in your component. I believe it all boils down to React detecting multiple copies of itself, even if they are the exact same version.

Issue(s):

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.

TypeError: Cannot read properties of null (reading 'useState')

Solution:

  1. Define your dependencies. Which of your packages is the 'library' (frontend) and which is the 'consumer' (server)?
  2. Follow the guidance at the bottom of this page (Invalid Hook Call Warning - Duplicate React) Read the guidance for npm link. Once understood, navigate to your 'library' project and run: npm link ../path/to/server-consumer/node_modules/react and npm link ../path/to/server-consumer/node_modules/react-dom
  3. Next, navigate to the 'library' project's node_modules folder and run ls -la If you don't see this output (symlink arrows): react -> ../path/to/server-consumer/node_modules/react and react-dom -> ../path/to/server-consumer/node_modules/react-dom then proceed to the next step.
  4. Verify that react has been npm linked correctly with npm ls -g --depth=0 --link=true This is good for npm. Then follow the last step.
  5. Finally, we will manually setup the links. If you followed the steps above, you've verified your npm link setup, but ls -la in your 'library'/node_modules is still not showing symbolic link arrows (->) for both react and react-dom. Navigate to 'library'/node_modules and run rm -rf react, rm -rf react-dom, ln -s ../path/to/server-consumer/node_modules/react react, ln -s ../path/to/server-consumer/node_modules/react-dom

Run your app and hopefully the React error will be resolved!

Reproducing

This error can be reproduced with this minimal setup.
node v18.19.0
npm v10.2.3
react v18.2.0
react-dom v18.2.0

{
  "name": "frontend-package",
  "version": "1.0.0",
  "description": "frontend library for server which will SSR",
  "type": "module",
  "main": "./dist/esm/main.js",
  "module": "./dist/esm/main.js",
  "browser": "./dist/web/main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "peerDependencies": {
    "react": "18.2.0",
    "react-dom": "18.2.0"
  }
}
{
  "name": "server-consumer",
  "version": "1.0.0",
  "description": "SSR server-consumer of frontend-package",
  "type": "module",
  "main": "./src/index.js",
  "scripts": {
    "start": "node src/index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies": {
    "frontend-package": "1.0.0",
    "express": "4.18.2",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  }
}

I hope this helps some people out there. Thank you!

@WebGearMT
Copy link

WebGearMT commented Feb 19, 2024

Hi there fellow Dev's, I am struggling with this issue to, mine is related to plugin development.

I created two functional components for a plugin in WordPress: one called edit (used in the back-end for displaying the plugin in the block editor) and another called RecentPosts (which is supposed to be integrated into edit.js for more functionality).

Here's the code for edit:

import './editor.scss';
import { useEffect, useState } from "react";
import RecentPosts from './recentPosts.js';


/**
 * The edit function describes the structure of your block in the context of the
 * editor. This represents what the editor will render when the block is used.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
 *
 * @return {Element} Element to render.
 */
export default function Edit(props) {
        // The state variables to be used for dynamically retrieving and modifying data.
        const [resourceType, setResourceType] = useState('news');
        const [latestPost, setLatestPost] = useState(null);
        const [serverUrl, setServerUrl] = useState('http://lab.local/news');
		const [error, setError] = useState(null);
    
        // https://react.dev/reference/react/useEffect

        async function fetchFeaturedMediaUrl(featuredMediaId) {
            try {
                const response = await fetch(`http://lab.local/wp-json/wp/v2/media/${featuredMediaId}`);
                const mediaData = await response.json();
                return mediaData.source_url;
            } catch (error) {
                setError(error);
                console.error('Error fetching featured media:', error);
                return null;
            }
        }

        function trimText(text, char_count) {
            try {
                if (text.length > char_count) {
		            const trimmedText = text.slice(0, char_count) + '...';
                    
                    return trimmedText;
	            }
            } catch (error) {
                setError(error);
                console.error('Error retrieving the text: ', error);
            }
        }

    useEffect(() => {
        function fetchLatestPostData() {
            let index = 0; // Initialize index to start from 0

            const interval = setInterval(async () => {
                try {
                    const response = await fetch(`http://lab.local/wp-json/wp/v2/${resourceType}`, {
                        method: 'GET',
                        mode: 'cors'
                    });
                    const posts = await response.json();

                    // Reset index if it reaches the end
                    if (index >= posts.length) {
                        index = 0;
                    }
                
                    // Get the post at current index
                    const firstPost = posts[index++]; 

                    // Trim title if available
                    if (firstPost.title.rendered) {
                        trimText(firstPost.title.rendered, 37);
                    }
                
                    // Fetch and set featured media URL if available
                    if (firstPost 
                        && firstPost.featured_media 
                        && firstPost.excerpt.rendered 
                        && firstPost.title.rendered) {
                        const featuredMediaUrl = await fetchFeaturedMediaUrl(firstPost.featured_media);
                        setLatestPost({
                            link: firstPost.guid.rendered,
                            title: firstPost.title.rendered,
                            excerpt: firstPost.excerpt.rendered,
                            featuredMediaUrl: featuredMediaUrl
                        });
                    } else if (firstPost) { // No featured media, title or excerpt are available
                        setLatestPost({
                            link: firstPost.guid.rendered,
                            title: null,
                            excerpt: null,
                            featuredMediaUrl: null
                        });
                    }
                } catch (error) {
                    setError(error);
                    console.error('Error fetching the data:', error);
                }
            }, 5000); // Set interval to 5 seconds

            return () => clearInterval(interval); // Clear interval on component unmount
        }
        fetchLatestPostData()
    }, [resourceType, serverUrl]);

    if (!latestPost) {
        return <p>No new posts available. </p>;
    }

    // Below is the user interface.
	return(
		<div className="newsBlock-wrapper">
            <div className="newsBlock-container">
                <span className='carrot'><img className='arrow' src='arrow.svg' /></span>
                <div key={latestPost.id} className="latestContent">
                    {(() => {
                            if (latestPost.featuredMediaUrl) {
                                return (
                                    <img
                                    src={latestPost.featuredMediaUrl}
                                    alt={latestPost.title}
                                    />
                                );
                            }
                            // If there is no featured media URL, return null or an empty fragment
                            return null;
                        })()}
                    <div className='latestContentInner'>
                        <h3 className="latestTitle">{latestPost.title}</h3>
                        <p className="latest-excerpt">{latestPost.excerpt}</p>
                        <p className="read-more-link"><a href={latestPost.link}>Read More</a></p>
                    </div>    
                                 
                    <RecentPosts />
                    
                </div>
            </div>
        </div>
	);
}

Here's the code for RecentPosts:

import './editor.scss';
import { useEffect, useState } from "react";
import  fetchFeaturedMediaUrl  from "./edit.js";




export default function RecentPosts() {
    // State Variables
    const [resourceType, setResourceType] = useState('news');
    const [Posts, setPosts] = useState([]);
    const [serverUrl, setServerUrl] = useState('http://lab.local/news');
    const [error, setError] = useState(null);

    

    useEffect(() => {
        const controller = new AbortController();
        // const signal = controller.signal;

        async function fetchData() {
        /* Retrieve the latest post's data from the WordPress API using the Fetch API.*/

            try {
                const response = await fetch(`http://lab.local/wp-json/wp/v2/${resourceType}`, {
                method: 'GET',
                mode: 'cors'
            });
            const newsPosts = await response.json();
            //const newsPostsArray = Object.values(newsPosts);
            const firstFive = newsPosts.slice(0, 5);
            
            const postData = await Promise.all(firstFive.map(async (post) => {
                const featuredMediaUrl = post.featured_media ? await fetchFeaturedMediaUrl(post.featured_media) : null;
                return {
                    link: post.guid.rendered,
                    title: post.title.rendered,
                    excerpt: post.excerpt.rendered,
                    featuredMediaUrl: featuredMediaUrl
                }
            }));

            setPosts(postData);

            } catch(error) {
                setError(error);
                console.error('Error fetching the data:', error);
            } 
        }
        fetchData();
        return () => {
            controller.abort();
        }
    }, [resourceType, serverUrl]);

    return(
        <div className="other-recent-posts">
            {Posts.length > 0 && Posts.map((post, index) => (
                <div key={index} className="post">
                    <h3>{post.title}</h3>
                    {/* Render image if available */}
                    {post.featuredMediaUrl && (
                        <img
                            className="orp-thumbnail"
                            src={post.featuredMediaUrl}
                            alt={post.title}
                        />
                    )}
                    <p>{post.excerpt}</p>
                    {/* Add more fields as needed */}
                </div>
            ))}
        </div>
    );
}

After running my scripts using the command npm run start, I got error error in the console when visiting the block editor where I added the plugin, it said this:
Error fetching the data: Error: Minified React error #321; visit https://reactjs.org/docs/error-decoder.html?invariant=321 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
Here's the full stack trace:

Error fetching the data: Error: Minified React error #321; visit https://reactjs.org/docs/error-decoder.html?invariant=321 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    bt react-dom.min.js:10
    useState react.min.js:10
    Edit edit.js:37
    postData recentPosts.js:31
    fetchData recentPosts.js:30
    RecentPosts recentPosts.js:47
    Ur react-dom.min.js:10
    El react-dom.min.js:10
    xl react-dom.min.js:10
    v react.min.js:10
    ce react.min.js:10
    t react.min.js:10
    <anonymous> react.min.js:10
    <anonymous> react.min.js:10
[recentPosts.js:44:24](webpack://news-block/src/recentPosts.js)
    fetchData recentPosts.js:44
    RecentPosts recentPosts.js:47
    Ur react-dom.min.js:10
    El react-dom.min.js:10
    xl react-dom.min.js:10
    v react.min.js:10
    ce react.min.js:10
    (Async: EventHandlerNonNull)
    t react.min.js:10
    <anonymous> react.min.js:10
    <anonymous> react.min.js:10

To solve this problem, I clicked on the link provided in the error which brought me to this page. After clicking on the link provided in the red box, I got to this page. Over there, I found a list and analysis of possible causes of this error, I checked for all of them but it turned out that I didn't make any of the mistakes they referred to or violated the rules for React hooks. I also prompted ChatGPT (3.5), it gave me the following response:

The error you're encountering, "Minified React error #321," typically occurs when React detects that a function component is called outside of the body of a function component, such as during initial render or a re-render. This error usually indicates that there might be a violation of the rules of Hooks.

In your code, the issue might be related to the asynchronous nature of the fetchData function within the useEffect hook. When calling fetchData, it initiates an asynchronous operation without returning a cleanup function. This could lead to the error you're experiencing.

To address this issue, you can try the following adjustments:

Ensure that the fetchData function is called inside the useEffect hook to prevent it from being called outside the body of the component.

Consider adding a cleanup function inside the useEffect hook to handle any cleanup needed when the component unmounts or before re-rendering.

Here's how you can refactor your code:

javascript

useEffect(() => {
    async function fetchData() {
        try {
            const response = await fetch(`http://lab.local/wp-json/wp/v2/${resourceType}`, {
                method: 'GET',
                mode: 'cors'
            });
            const newsPosts = await response.json();
            const firstFive = newsPosts.slice(0, 5);
            
            const postData = await Promise.all(firstFive.map(async (post) => {
                const featuredMediaUrl = post.featured_media ? await fetchFeaturedMediaUrl(post.featured_media) : null;
                return {
                    link: post.guid.rendered,
                    title: post.title.rendered,
                    excerpt: post.excerpt.rendered,
                    featuredMediaUrl: featuredMediaUrl
                };
            }));

            setPosts(postData);

        } catch(error) {
            setError(error);
            console.error('Error fetching the data:', error);
        } 
    }

    fetchData();

    // Optionally, add a cleanup function here if needed

}, [resourceType, serverUrl]);

By ensuring that the fetchData function is called within the useEffect hook and handling any cleanup if necessary, you can mitigate the "Minified React error #321" issue.

As it seems to me, my code basically looks the same, as you'll see, fetchData() is also in the useEffect() function and there is a cleanup function for both these components.

I am not completely sure what could be causing this error. It only occurs When RecentPosts() is included in edit (i.e. import RecentPosts from './recentPosts.js'). When I comment the statements out, the error is gone. If any one has a solution to this problem it would be greatly appreciated.

@Abulkalam-Asif
Copy link

Abulkalam-Asif commented Apr 22, 2024

Please help me resolve this problem.
I am working on a Project in Next.js and have been facing this error and nothing is helping me resolve it.

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.
 ⨯ TypeError: Cannot read properties of null (reading 'useContext')
    at ReadyProjectClientPage (./src/components/admin-side/ready-project/ReadyProjectClientPage.js:31:76)
digest: "3449185741"

Here is the ReadyProjectClientPage.js file mentioned in the error:

"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { AlertContext } from "@/context/AlertContext";
import { useContext } from "react";
// Other imports

const ReadyProjectClientPage = (props) => {
  const { showAlert } = useContext(AlertContext);
  const addReadyProjectS1Handler = async e => {
    e.preventDefault();
    // addReadyProjectS1Service is a function which runs on the client, checks the input before passing it to the Firebase server action function to add the data to database. No hook is called in this function, however, `showAlert()` returned by the `useContext(AlertContext)` is passed to this function to be called in case of invalid input.
    const data = await addReadyProjectS1Service(
      readyProjectS1,
      showAlert,
      setShowSpinner,
    );
  }
 // showAlert passed to other similar functions as well

  // Other code
  return (
    <>
      {/* JSX */}
    </>
  )
}

The main issue is that I am unable to reproduce the problem. The error appears randomly, once in a few hours, mostly when I reload the page. After it appears, no matter how hard may I try to reproduce it, it would not reappear.

I have manually checked all the hooks and they are all directly inside React components.

Here is my AlertContext.js file:

"use client";
import { createContext, useState } from "react";
const AlertContext = createContext({
  alerts: [],
  showAlert: () => {},
  hideAlert: () => {},
});

const AlertProvider = ({ children }) => {
  const [alerts, setAlerts] = useState([]);

  const showAlert = ({ type, message }) => {
    setAlerts([{ type, message, timestamp: Date.now() }]);
  };

  const hideAlert = () => {
    setAlerts([]);
  };

  return (
    <AlertContext.Provider value={{ alerts, showAlert, hideAlert }}>
      {children}
    </AlertContext.Provider>
  );
};

export { AlertProvider, AlertContext };

Here is my root layout.js file in which I have put the AlertProvider:

import { Roboto } from "next/font/google";
import "@/app/globals.css";
import { AlertProvider } from "@/context/AlertContext";
import StoreProvider from "@/store/StoreProvider";

const roboto = Roboto({
  subsets: ["latin"],
  weight: ["100", "300", "400", "500", "700", "900"],
});

export const metadata = {
  title: "title",
  description: "description",
};

export default function RootLayout({ children }) {
  return (
    <>
      <StoreProvider>
        <AlertProvider>
          <html lang="en">
            <body className={roboto.className}>{children}</body>
          </html>
        </AlertProvider>
      </StoreProvider>
    </>
  );
}

The versions of react and react-dom are both 18.
I visited the this link to React official site provided in the error description.
Under the Duplicate React section, it says:

If you use Node for package management, you can run this check in your project folder:
npm ls react
If you see more than one React, you’ll need to figure out why this happens and fix your dependency tree.

I ran the command on my terminal and here is the result:

PS C:\Users\user\Desktop\project> npm ls react
project@0.1.0 C:\Users\user\Desktop\project
+-- @reduxjs/toolkit@2.2.3
| `-- react@18.2.0 deduped
+-- next@14.2.1
| +-- react@18.2.0 deduped
| `-- styled-jsx@5.1.1
|   `-- react@18.2.0 deduped
+-- react-dom@18.2.0
| `-- react@18.2.0 deduped
+-- react-icons@5.1.0
| `-- react@18.2.0 deduped
+-- react-redux@9.1.1
| +-- react@18.2.0 deduped
| `-- use-sync-external-store@1.2.0
|   `-- react@18.2.0 deduped
+-- react-slick@0.30.2
| `-- react@18.2.0 deduped
`-- react@18.2.0

Then it says:

You can also try to debug this problem by adding some logs and restarting your development server:

// Add this in node_modules/react-dom/index.js
window.React1 = require('react');

// Add this in your component file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);

I tried it in my current Next.js project,in a new Next.js project, and in a new React.js project using vite.
I noticed that in any Next.js project, window.React1 pasted in node_modules/react-dom/index.js is not accessible in any component and returns undefined, so console.log(window.React1 === window.React2); always returns false. However in the React project, window.React1 pasted in node_modules/react-dom/index.js is accessible in React components and returns an object.

I have also added react and react-router-dom to peer-dependencies as mentioned in another answer.

{
  "name": "mehraz",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@reduxjs/toolkit": "^2.2.3",
    "firebase": "^10.11.0",
    "next": "14.2.1",
    "react-icons": "^5.1.0",
    "react-redux": "^9.1.1",
    "react-slick": "^0.30.2",
    "slick-carousel": "^1.8.1",
    "ulid": "^2.3.0"
  },
  "peerDependencies": {
    "react": "^18",
    "react-dom": "^18"
  },
  "devDependencies": {
    "autoprefixer": "^10.4.19",
    "eslint": "^8",
    "eslint-config-next": "14.2.1",
    "postcss": "^8.4.38",
    "tailwindcss": "^3.4.3"
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests