Duplicated React instance when NPM link a React package. Invalid hook call

I'm currently building a React design system library. I'm using Rollup.js as bundler.

The goal is improve the developer experience working with this DS (Design system) package, using NPM link in the host application to install DS and works locally. When I use npm link in the host application to use DS, then run the host application, the console throws to me Invalid hook call. I've tried all this issue explains and I can't solve it. This problem occurs when you have two instances of React, and I have it when I use npm link.

If I push the DS library on my remote repo and install it from GH, it works perfectly, something like this:

"design-system-library": "git://github.com/some-org/design-system-library.git#some-branch-name",

As I have the dist folder inside the files key in my package.json, when I install it from my remote repo, my node_modules only have the dist folder. When I use npm link all the files are in my node_modules

This is my design system library package.json

{

  "version": "0.1.0",
  "private": true,
  "main": "dist/main.cjs.js",
  "files": [
    "dist"
  ],
  "scripts": {},
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "peerDependencies": {
    "@material-ui/core": "^4.11.4",
    "@material-ui/icons": "^4.11.2",
    "@material-ui/lab": "^4.0.0-alpha.58",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "styled-components": "^5.3.0"
  },
  "devDependencies": {
    "@babel/cli": "^7.14.5",
    "@babel/core": "^7.14.6",
    "@babel/preset-env": "^7.14.7",
    "@babel/preset-react": "^7.14.5",
    "@rollup/plugin-babel": "^5.3.0",
    "@rollup/plugin-commonjs": "^19.0.0",
    "@rollup/plugin-node-resolve": "^7.1.3",
    "@svgr/rollup": "^5.5.0",
    "react-router-dom": "^5.2.0",
    "rollup": "^2.52.2",
    "rollup-plugin-copy": "^3.4.0",
    "rollup-plugin-css-only": "^3.1.0",
    "rollup-plugin-delete": "^2.0.0",
    "rollup-plugin-peer-deps-external": "^2.2.4",
    "styled-components": "^5.3.0"
  }
}

As you can see, I've react and react-dom as peerDependencies. This is my rollup.config.js file:

import babel from "@rollup/plugin-babel";
import commonjs from "@rollup/plugin-commonjs";
import svgr from "@svgr/rollup";
import copy from "rollup-plugin-copy";
import del from "rollup-plugin-delete";
import external from "rollup-plugin-peer-deps-external";
import css from "rollup-plugin-css-only";
import resolve from "@rollup/plugin-node-resolve";

import pkg from "./package.json";

console.log(Object.keys(pkg.peerDependencies));

const config = {
  input: "src/index.js",
  output: [
    { file: "dist/main.cjs.js", format: "cjs" },
    { file: "dist/index.esm.js", format: "esm" },
  ],
  plugins: [
    external(),
    resolve({
      customResolveOptions: {
        moduleDirectory: "node_modules",
      },
      dedupe: [...Object.keys(pkg.peerDependencies)],
    }),
    babel({
      exclude: "node_modules/**",
      babelHelpers: "bundled",
    }),
    del({ targets: ["dist/*"] }),
    svgr(),
    css({ output: "index.css" }),
    copy({
      targets: [
        { src: "src/assets/fonts", dest: "dist/assets" },
        { src: "src/assets/*.jpg", dest: "dist/assets" },
      ],
    }),
    commonjs(),
  ],
  external: [...Object.keys(pkg.peerDependencies)],
};

export default config;

I would like to use my DS in my host application. If I use npm link and then I go to my host node_modules I've installed all my DS files included one playground app inside the the DS repo. This playground application is used to take a fast look about new components.

The DS project structure is something like this: Design system project structure

The "demo" application uses react too but it works perfect because the react and react-dom that it uses is the same as the DS. This is the demo's package.json. I add this information because I don't know if can be possible that the problem where here.

{
  "name": "demo",
  "version": "0.1.0",
  "private": true,
  "devDependencies": {
    "design-system-library": "file:..",
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "web-vitals": "^1.1.2"
  },
  "peerDependencies": {
    "react": "../node_modules/react",
    "react-dom": "../node_modules/react-dom",
    "react-scripts": "4.0.3"
  },
  "scripts": {
    "start": "react-scripts start"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

Upvotes: 4

Views: 777

Answers (1)

Md Joynul Abedin
Md Joynul Abedin

Reputation: 250

You can be seeing it for one of three typical causes:

1.The versions of React and React DOM you have might not be compatible: It's possible that the version of react-dom  you're using ( <16.80 ) doesn't currently support Hooks. To find out which version you're running, use npm ls react-dom command in your application folder. Problems may arise if you locate more than one instance of them.

2.The Rules of Hooks may not be being followed by you: Call them at the top level in a function component's body, or at the top level in a custom Hook's body.

Hooks should not be called from class components,should not call nside Event handlers, in functions supplied to useMemo, useReducer, or useEffect, should not call Hooks.

3.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, rather just mention them as peerDependencies ( in your case already done)

2.(how usually I solve this issue when using webpack): mention inside the webpack.config.js file :

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

get the concept : some how manage to have only single instance of react.

Upvotes: 0

Related Questions