I'm developing a React module locally. For that, I'm linking my module using npm link
.
The module is imported successfully but hooks are failing inside the module. It's throwing the following error:
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.
Checking the suggestions at React docs, I can confirm my app is using duplicate versions of React since the following code returns false:
// node_modules/mymodule/src/index.js
export { default as ReactFromModule } from 'react'
// src/index.js
import React from 'react'
import { ReactFromModule } from 'mymodule'
console.log(React === ReactFromModule) //false
This issue is full of suggestions but they are confusing. How can I solve it?
Note: Im not breaking rules of hooks, the error appears only when importing the module from an application.
4 answers. In the module you are developing, add the conflicting packages to peerDependencies (and remove them from dependencies or devDependencies ): // package. json "peerDependencies": { "react": "16.13.
The use cases for having multiple pages in a single React app are pretty simple. You can create a website, and easily classify different types of content on different pages. But, it should also be understood that the default implementation of React is made to use a single HTML file, and this is by design.
We can divide the UI of the application into small components and render every component individually on the web page. React allows us to render one component inside another component. It means, we can create the parent-child relationship between the 2 or more components.
If you just want the two apps to merge fully together, I would recommend merging the src folders together (possibly manually) along with any dependencies (i.e. combining the package. json files) and then re-running npm install.
If you use webpack to build your application, you can use the resolve.alias configuration option to make sure that all modules refer to the same react library: If you use web pack then you can fix it by adding the following to Webpack config and if you don't use webpack?
Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded I have tried many solutions from diff forum but none of them worked.I am sure problem is of multiple copies of react.
In response to another comment, merely moving React to peerDependencies does not adequately resolve the issue in all cases. I would reply to that comment directly, but StackOverflow requires more reputation to respond to wrong answers than it does to post them.
In the module you are developing, add the conflicting packages to peerDependencies (and remove them from dependencies or devDependencies ): Execute npm install in your module. Now add react and react-dom to the webpack configuration of your module as externals.
In the module you are developing, add the conflicting packages to peerDependencies
(and remove them from dependencies
or devDependencies
):
// package.json
"peerDependencies": {
"react": "16.13.1",
"react-dom": "16.13.1"
},
Execute npm install
in your module.
Now add react
and react-dom
to the webpack configuration of your module as externals
. These packages shouldnt be included in the bundle of the module (the app that uses the module will provide them):
// webpack.config.js
module.exports = {
/*
rest of config...
*/
output: {
filename: "index.js",
pathinfo: false,
libraryTarget: 'umd', // In my case, I use libraryTarget as 'umd'. Not sure if relevant
},
externals: {
// Use external version of React
"react": {
"commonjs": "react",
"commonjs2": "react",
"amd": "react",
"root": "React"
},
"react-dom": {
"commonjs": "react-dom",
"commonjs2": "react-dom",
"amd": "react-dom",
"root": "ReactDOM"
}
},
};
Then, after building your module, in your application you can check that both versions are now the same:
// node_modules/mymodule/src/index.js
export { default as ReactFromModule } from 'react'
// src/index.js
import React from 'react'
import { ReactFromModule } from 'mymodule'
console.log(React === ReactFromModule) // true :)
In response to another comment, merely moving React to peerDependencies does not adequately resolve the issue in all cases. I would reply to that comment directly, but StackOverflow requires more reputation to respond to wrong answers than it does to post them.
I have a shared React component module built using Webpack and have run into the same issue. I've outlined one possible fix in this comment below which requires modifying peerDependencies and using npm link in a fashion similar to the answer shared by mtkopone. https://github.com/facebook/react/issues/13991#issuecomment-841509933
My solution is a bit hacky and I wouldn't recommend it for long-term use. If you are using Webpack (which you tagged this question as), this article may detail a more permanent solution (https://medium.com/codex/duplicate-copy-of-react-errors-when-using-npm-link-e5011de0995d). I haven't tried it yet, but the author seems to have tried all the (incorrect) solutions out there and is also running into the hooks issue while trying to build shared component libraries.
The author of that article is trying to debug a Create-React-App app. While CRA uses webpack under the hood, you can't access the webpack.config directly, so the author has to perform some workarounds to do so. If you aren't using CRA, but just plain Webpack, then you could consider using the resolve.alias section of webpack.config to ensure there are no duplicate copies of React (see: https://blog.maximeheckel.com/posts/duplicate-dependencies-npm-link/)
Adding react
and react-dom
as peerDependencies
in the package.json
didn't work for me.
I had to add an alias to the webpack configuration file:
// webpack.config.js
resolve: {
alias: {
react: path.resolve('./node_modules/react'),
}
I was attempting to use the peerDependencies
and removal of the devDependencies
and it was failing.
It turned out I had a node_modules
folder in one of the parent folders of the library I was working on and the duplicate version of React was being loaded from there instead of the tool that was trying to use the React library.
Rather than editing the devDependencies
to remove react I just wrote a small script to delete anything that's in the peerDependencies
from the node_modules
folder.
npm view --json=true . peerDependencies | jq -r 'keys | .[] | @text' | while read dep; do rm -r ./node_modules/${dep} && echo Removed ${dep}; done
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With