Duplicate React after downloading npm package - reactjs

I have an npm package (that I published) which causes duplicate React instances and hence the following Component Exception:
"Invalid hook call. Hooks can only be called inside of the body of a function component..."
What should I do in order to prevent this error from occurring in projects that download this package?

EDIT: The following answer relates to publishing a package and not installing.
For future generations (and current) in case you came across with the same issue, meaning that you ran npm ls react and saw 2 different instances of React. The problem is due to the fact that React should be in your package.json under the peerDependencied and not under dependencies.
You can find a lot of info about it online but I recommend reading this article as it simplifies the subject and makes it clear.

Within a single app, React may exist in several instances (the most probable reason):**
If you use Node for package management, you can run to check the React duplicity in your project folder:
npm ls react
to slove the issue : 1. don't use react , react-dom as dependencies or devDepenencies in your published package's package.json file, rather just mention them as peerDependencies
2.(how usually I solve this issue): mention inside the webpack.config.js file :
resolve: {
alias: {
react: path.resolve("./node_modules/react"),
},
},

Simple, when you create your package, dont specify any version to react
in dependency add "react:": "*"
This will mean that it will use whatever react version that are installed on the user project

Related

Trying to create a shareable React component - but failing to import it

I'm trying to share a React component I've created through a local hosted npm repo.
To do that I created the React component with typescript, transpiled it to js and published the resulting code to the repo. But when I install this package in an existing project (a basic create-react-app project with typescript) and try to use that component - My app tried to compile it for a few minutes and I fail to load that component. Sometimes if I wait a few minutes I see this error - although the component was tested and works:
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:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
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.'
I've copied the same component to be embedded in the app and not installed by npm - it worked. I tried to strip the component to the bare minimum - it still takes a long time.
The steps to reproduce are easy:
I've shared the component in github:
https://github.com/ymoran00/example-stackoverflow-react
To build it you need to run npm install and then npm run build.
the result will be generated in the lib folder.
You can then go into the lib folder and run:
npm link
Then create a new typescript create-react-app project:
npx create-react-app my-app --template typescript
Go inside it and run:
npm link login-component
This will install the linked package.
Now go to App.tsx and import the package:
import LoginContainer from 'login-component/LoginContainer';
And use it in the App:
<LoginContainer onLogin={()=> {alert('success')}}/>
Run the app with npm start.
The App will open the browser - but nothing will load. It's kind of stuck on build or whatever - I don't know what happens there. If you'll take a look at the component you'll see it's quite a basic one with Material-UI.
The first place that I looked was your package.json file because it most likely that you are dealing with reason #1:
You might have mismatching versions of React and the renderer (such as React DOM)
I see that you are including react and react-dom as dependencies for your component. You should move these from dependencies to peerDepenedencies. You likely want to move #material-ui/core and #material-ui/icons to peerDependencies as well. Right now React is being bundled with your component and your component uses its own React version rather than the one in your app. You want to make it so that projects that use your component are expected to include React on their own.
For more information about why you should use peerDependencies, see this question:
What's the difference between dependencies, devDependencies and peerDependencies in npm package.json file?
It seems that the main problem I had in the process is using npm link.
It causes problems when combined with hooks - that's why I get this hooks error.
See also in this thread:
https://github.com/facebook/react/issues/13991
So instead of using npm link I've started using npm-sync and it seems to solve the problem.

Potential security threat detected in build errors in a fresh create-react-app install (script accessing "/initrd.img", "/vmlinuz" and others)

After I have created a new app with create-react-app or Razzle, error messages appear at build time which are quite concerning, security wise:
[Error: ENOENT: no such file or directory, stat '/initrd.img'] {
errno: -2,
code: 'ENOENT',
syscall: 'stat',
path: '/initrd.img'
}
Sometimes, a few other messages appear, with "/vmlinuz" "/initrd.img.old", "/vmlinuz.old" and ".steampath" instead.
Theses messages appear any time there's a build error (any build error that I generate).
This is basically the same problem as described in vue-CLI outputting very concerning error (security question) (but I was told to ask a new question). There were testimonies of three people having the same error messages in that thread.
I don't think there would be any valid reason for a React build script to stat the Linux kernel and a Steam directory, so there might be a malicious package at play here.
This only happens with npm, not yarn. (If your app has been created by CRA with yarn, you should do rm -rf node_modules && rm -rf yarn.lock && npm install);
The most minimal setup I could achieve while trying to isolate the culprits was:
creating a brand new app with create-react-app with npx create-react-app app1
and then generating an arbitrary build error in index.js, adding something like: import "nonexistent";
When I do that, I see the stat '/initrd.img'error mentioned above.
I'd like to know if you don't see the errors after executing the same exact steps. That would probably mean that it doesn't come from the packages installed but from elsewhere in my system.
It cannot come from my Node.js setup though, because I deleted my $HOME/.nvm, $HOME/.npm $HOME/node_modules, $HOME/.yarn and $HOME/.config/yarn before redoing the steps below.
There aren't many similar testimonials about this on the web, apparently. A bit more with "/.steampath" though.
I reported the issue to security#npmjs.com. They haven't replied yet.
If there is indeed a malicious script in the dependency tree of react-create-app (and Razzle), it should be investigated urgently.
Environment:
Node 14.14 installed with nvm 0.36.0
npm 6.14.8
create-react-app 3.4.1
Kubuntu 20.04
EDIT: I've also posted an issue at https://github.com/facebook/create-react-app/issues/9855. I thought this was serious and urgent enough that CRA maintainers should be notified now.
I got the same error and struggled with it for 2 days. Everything was running well on my Mac but as soon as I cloned the GitHub repository and tried to run my react app on the Linux system as well as AWS-Amplify and it showed me this same error:
[Error: ENOENT: no such file or directory, stat '/initrd.img'].
But after checking the build error logs I found that it was the problem with an import from react-bootstrap. The problem was 'the case' of the component I was importing. In my case I was importing bootstrap Container and used container instead of Container.
I simply corrected that and everything was resolved.
In my case:
WRONG: import Container from 'react-bootstrap/container'
RIGHT: import Container from 'react-bootstrap/Container'.
My Tip: Trivial mistakes like this can also give you this error. Check for incorrect imports and see the documentation for the libraries to check the cases.
In case your application is small and you have not gone too far with the development, then you can create a new react application and copy the component files one by one and run them to see which component is actually creating the problem. This is not the best idea but it worked for me the first time I got this error.
PS: Thank you for reading. This is my first answer on Stack Overflow. YAY!
There seems to be a simple answer: these messages could just come from Node searching for node_modules in the project parent directories all the way to the filesystem root. (See https://nodejs.org/api/modules.html#modules_loading_from_node_modules_folders). It might also try to follow symlinks in case they point to a node_modules directory, and emit an error each time it encounters a broken symlink in the process.
That's plausible and reassuring. No malicious script involved.
I removed initrd.img, /initrd.img.old, /vmlinuz and /vmlinuz.old, which were indeed broken symlinks. So I shouldn't get these errors anymore.
In my case it was an incorrect import statement of a static CSS file in my react-app.
VS Code for some reason auto imported a "classes" object from some random route when trying to declare const classes = useStyles(); using Material UI makeStyles method.
So check if you have any incorrect import statements of files.
In my case the message appeared when I installed new #mui/material ui lib without #emotion/react #emotion/styled complement
The missing library name was written in the error message in the console, but I had to catch it with PrtSc cause the message mentioned above replaces it almost immediately.
Node.js tries to find modules in the parent directories, up to the root. Possibly in your /boot there is a broken symlink. The message indicates that there is a package not found or a mispelled import in your codebase.
In my case this error fix manual installing react-router-dom npm i react-router-dom
For me, an npm package was missing in the package.json. Installing the package with npm install --save <package> solved the issue
In my case, an import syntax error. I had forgotten the first forward slash before 'components/MyComponent'.
In my App.js:
import MyComponent from '..components/MyComponent'
change by:
import MyComponent from '../components/MyComponent'
The same error message occurred to me. After removing all files at node_modules and running npm install to reinstall them, it says the node-sass dependency failed to run, then after rebuilt of the dep, the error disappeared.
I also saw this error. For me the reason was that I was not installing the npm package in my project directory but in some other directory.
I noticed package.json and package-lock.json in my project were not getting updated even after running npm install --save <package_name>

I am trying to build NPM module with React Hooks and Webpack , so after Publishing package when i try to use it's giving Invalid Hook call Error

so after publishing package when i import it in local application then it's giving me
There are three common reasons you might be seeing it:
You might have mismatching versions of React and React DOM.
You might be breaking the Rules of Hooks.
You might have more than one copy of React in the same app.
after some googling i have checked with npm ls react command and it show me only 1 version available and i guess that's not an issue in case,hence i have change it to class based component to make it work.
So i would like to know is there any way to implement react hooks in npm module with webpack or any other way if possible ?

Getting error when using FormattedMessage inside a module: Error: [React Intl] Could not find required `intl` object

I have a monorepo which exposes a TypeScript module, which is consumed & used by a React TypeScript project.
When the module inserts arbitrary React elements to the virtual DOM - everything works as expected, including when I try to use React Router (which was initially problematic but I was able to fix that).
However, when I try to use react-intl, via FormattedMessage, I get the error:
Error: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.
Which is especially annoying as I see this printed in the console logs:
The above error occurred in the <Context.Consumer> component:
in FormattedMessage
in h2
in div
in Loading (at App.tsx:11)
in IntlProvider (at App.tsx:8)
in App (at src/index.tsx:9)
in StrictMode (at src/index.tsx:8)
(note the IntlProvider wrapping Loading - which is the element that uses FormattedMessage which can't find IntlProvider).
I imagine this is somehow related to versioning, or having 2 instances of React / React DOM / IntlProvider, but I have no idea to how solve this, and I have spent quite a lot of time trying everything I could think of.
For what it's worth, here's what I use:
TypeScript - for both module and project
Webpack to pack the module, where I declared React, ReactDOM and react-intl as externals and added them as peerDependencies rather than direct dependencies
create-react-app for the project
I was able to create a minimal repro repository, here's how to repro my issue:
<cd somewhere>
git clone https://github.com/chakaz/repro-repo .
cd repro-lib
npm install
npm run build:dev
cd ../project
npm install
npm run start
Anyone has any idea? Tons of thanks in advance!
With your above way in order to make it work, you have to delete node_modules in your repro-lib dir cause it will install dependencies in both dirs.
So in order to resolve problem of monorepo, I'd like to suggest you use yarn's workspace functionality as described carefully here: https://classic.yarnpkg.com/en/docs/workspaces/
To summary, it's a great functionality to help working with multiple workspaces by just only yarn install once.
Here are a few steps to make your repo working:
Put package.json at the root level of the project with following content:
{
"private": true,
"workspaces": ["project", "repro-lib"]
}
Go to project dir and replace following line in package.json:
"pf-common": "file:../repro-lib"
to
"pf-common": "1.0.0"
Finally, just go back to root top level install deps again:
yarn install
That's it! Now you can re-run your application to see how it works.
NOTE: In terms of having interest in monorepo, lerna is also great tool comes to help by providing great CLI.

How to avoid `loaded two copies of React` error when developing an external component?

I am developing an external component (let's say my-component, which I link to the project with npm link (as it is in process and I need the package to reflect changes).
In the my-component folder there are node_modules/react and node_modules/react-dom as they are its dependencies. However they are peerDependences, so I did not suppose to bring them into the project linking this package.
However when using npm link, it link the whole directory, including node_modules. So, when the project builds, it includes packages 2 times: from node_modules/* and from node_modules/my-component/node_modules/*.
This begins to affect when the component is using ReactDOM.findDOMNode, it causes this error:
Warning: React can't find the root component node for data-reactid value `.0.2.0`. If you're seeing this message, it probably means that you've loaded two copies of React on the page. At this time, only a single copy of React can be loaded at a time.
Also, it may help to understand what's happening: the problem only appears if there are both node_modules/my-component/node_modules/react and node_modules/my-component/node_modules/react-dom. If there is only one of them, there is no error message.
The usual package installation does not bring such error as there is no node_modules/react-dom there.
How is it supposed to develop an external component and the project at the same time?
The issue is twofold:
You cannot have 2 copies of react loaded.
npm link creates a symlink, however the "require" doesnt respect the
symlink and when it tries to navigate up the directory, it never
finds the react of the parent project.
Solution:
All you have to do is link the react and react-dom in your component to that of parent project's node_modules folder.
Go to your component project and remove the react and react-dom then do
npm link ../myproject/node_modules/react
npm link ../myproject/node_modules/react-dom
Fixed it by adding react-dom as an alias to my webpack config
alias: {
react$: require.resolve(path.join(constants.NODE_MODULES_DIR, 'react')),
'react-dom': require.resolve(path.join(constants.NODE_MODULES_DIR, 'react-dom'))
}
Someone clevererer than I (#mojodna) came up with this solution: remove the duplicate dependencies from the external component, and resolve them with your project's copies of those deps.
Step 1: Remove the dependencies from your external component's node_modules
As #cleong noted, you can't just remove the deps from the external component's node_modules, because your project's build step will fail when it hits the now-missing dependencies in the external component.
Step 2: Add your project's node_modules to NODE_PATH
To fix this, you can append the project's node_modules to the NODE_PATH environment variable when running your build step. Something like e.g. this:
NODE_PATH=$(pwd)/node_modules/ npm start
(where npm start is your script that bundles your external component, via e.g. Browserify, Webpack, etc.)
In fact, you could always append that NODE_PATH addition to your build scripts, and it would work whether or not you've npm linked anything. (Makes me wonder if it shouldn't be default npm behavior...)
Note: I left my existing answer because there's some conversation there, and this is a different (and better) solution.
I believe the answer is to specify react and react-dom as peerDependencies in your external component's package.json. As best as I can follow here and here, npm link should (as of npm#3) no longer install peerDependencies (or `devDependencies either).
Aaaand I just read your post more carefully and realized that you already are specifying them as peerDependencies. Therefore, I think the answer boils down to:
Upgrade to npm#3:
npm install -g npm#3.0-latest
The problem is with npm link. https://github.com/npm/npm/issues/5875
npm doesn't treat the linked directory as a child of the parent project.
Try alternatives to npm link:
1) Use relative path dependencies in package.json
2) Manually include your dependencies in your projects node_modules directory
3) Use url path
Basically anything but npm link
I am using ReactJS.net and setup webpack from the tutorial there and started using react-bootstrap aswell when i started getting this error. I found adding 'react-dom': 'ReactDOM' to the list of externals in webpack.config.js fixed the problem, the list of externals then looked like this:
externals: {
// Use external version of React (from CDN for client-side, or
// bundled with ReactJS.NET for server-side)
react: 'React',
'react-dom': 'ReactDOM'
This seems to be the first stack overflow link on google for this error, so i thought this answer might help someone here.
Adding the following in my webpack.config.js worked for me:
resolve: {
alias: {
react: path.resolve(__dirname, 'node_modules', 'react')
}
}
I also experimented with DedupePlugin (mentioned as a possible remedy here) but I couldn't get it to work.
What's also interesting is that I've encountered different (and perhaps more insidious) manifestations of the same problem when a module is found in multiple places in the dependency graph.
One such case was that my React.PropTypes.instanceOf(SomeType) constraints would emit warnings even though the type I passed in was correct. That was due to the module being present in multiple places in the node_modules directory tree. Due to duck-typing the code would still work, but my console was cluttered with these warnings. Going the resolve.alias way silenced those too.
YMMV
Strongly recommend using https://github.com/mweststrate/relative-deps.
Installs dependencies from a local checkout, and keeps them in sync, without the limitations of link.
This fixes the issue as it installs the local library just as npm install would, satisfying any dependency versions, etc.
If you're using Webpack in the main project, this solution may work. In my case, project-a requires project-b. Both require React and ReactDOM 0.14.x
I have this in project-a/webpack.config.js:
resolve: {
modulesDirectories: ['node_modules'],
fallback: path.join(__dirname, 'node_modules')
},
resolveLoader: {
fallback: path.join(__dirname, 'node_modules')
},
project-b requires React and ReactDOM as peerDependencies in project-b/package.json
project-a requires project-b as a devDependency (should also work required as a dependency) in project-a/package.json
local project-b is linked to project-a like so: cd project-a; npm link ../project-b
Now when I run npm run build within project-b, the changes appear immediately in project-a
I was getting this because I had already included react and react-dom as external scripts in my HTML markup.
The error was caused by adding an import ReactDOM from 'react-dom' to a component module. The error went away once I removed the import, and the module worked fine since the components were already available.

Resources