Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Link react versions between linked library and workspace application

I'm developing a React library for my common used components. In my root folder where there is:

  • my rollup config and my src/ folder containing my library. When it's build, the bundle files (ES, CJS and UMD) are in the dist/ folder.
  • my workspace: a simple parcel bundled app where there is an independent package.json. In this package.json, myLib is in dependencies and I linked it.

When I want to use myLib in the workspace I import it like this: import { Button } from 'myLib'.

Here, everything seems to be okay. But in a component I'm using a hook and I have this error:

Uncaught Invariant Violation: 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

It seems there's two copies of React, npm ls react returns:

└─┬ [email protected] invalid
  └── [email protected]  extraneous

I tried to link react and react-dom between myLib/ and workspace/ node_modules but it never works and this error is still here.


TLDR;

Here's my file tree:

myLib
│   package.json
│   rollup.config.js
│
└───dist/
│
└───src/
│   │   **
│
└───workspace
│   │   package.json
│   │   index.js

To link myLib to workspace: I go to myLib/ and I do yarn link then I go to workspace/ and I do yarn link myLib

react and react-dom are peerDependencies in myLiband devDependencies in workspace/


Oh course I already looked here:

  • https://reactjs.org/warnings/invalid-hook-call-warning.html
  • https://github.com/facebook/react/issues/13991
  • https://github.com/facebook/react/issues/15315
  • https://github.com/facebook/react/issues/15628
like image 373
Bastien Robert Avatar asked Jul 22 '19 11:07

Bastien Robert


People also ask

Can I use multiple react versions?

You can try to place react in both peerDependencies and devDependencies. Placing it in dependencies (without peer or dev) will cause multiple versions of React to be installed.

How can you tell multiple copies of a react?

So the simple solution to the You might have more than one copy of React in the same app error is to add rules into the bundler's config (webpack discussed here but similar approaches are available for other bundlers such as Snowpack, rollup. js or Parcel).

How do you solve You might have more than one copy of react in the same app?

Method 1. 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.


3 Answers

The solution for this issue is actually explained in the react doc:

This problem can also come up when you use npm link or an equivalent. In that case, your bundler might “see” two Reacts — one in application folder and one in your library folder. Assuming myapp and mylib are sibling folders, one possible fix is to run npm link ../myapp/node_modules/react from mylib. This should make the library use the application’s React copy.

Another solution is to use lerna (with hoisting).

like image 106
Bastien Robert Avatar answered Oct 19 '22 20:10

Bastien Robert


I found an answer that worked for me here: How to avoid React loading twice with Webpack when developing

I spent a bit of time with this problem, yet the answer was simple. If you are having multiple versions of React, you have to go to your workspace and link to the version of React in myLib.

like image 41
MarshHawk Avatar answered Oct 19 '22 21:10

MarshHawk


Here is a simple solution that works with yarn and npm:

cd /your-library/node_modules/react
yarn link
cd /your-library/node_modules/react-dom
yarn link
cd /your-app
yarn link react
yarn link react-dom

Ensure that your-library has React version compatible with your-app.

Alternatively, if you are using webpack, just configure alias:

alias: {
  react: path.resolve(__dirname, './node_modules/react'),
  'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
},
like image 1
Gajus Avatar answered Oct 19 '22 19:10

Gajus