Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Importing and using component from custom React Component Library results in Invariant Violation: Invalid hook call

My work is making a React UI Kit/Component Library to be used internally for our products. Everything is working fine while developing and displaying on Storybook.

While testing the library in a generic project out-of-the-box from create-react-app, importing and implementing the components made without React Hooks are alright, but soon as we use the ones made with Hooks - the Invalid Hook Call error shows: https://reactjs.org/warnings/invalid-hook-call-warning.html

Have tried everything listed there(and read and tried the github thread solutions linked on the page), and the component simply used useRef() and nothing else so we know no rules were broken, React and React-dom versions are up to date, and running npm ls react and npm ls react-dom in the project results in [email protected] and [email protected] and nothing else... So it doesn't seem like we have multiple React's?

Any help would be much appreciated!!

This is the UI Kit's package.json

{
    "name": "react-ui-kit",
    "version": "0.0.15",
    "description": "UI Kit",
    "main": "dist/index",
    "module": "dist/index",
    "typings": "dist/index",
    "jest": {
        "setupFilesAfterEnv": [
            "<rootDir>/setupTests.js"
        ],
        "coverageReporters": [
            "json-summary",
            "text",
            "lcov"
        ]
    },
    "scripts": {
        "test": "jest --coverage",
        "test:badges": "npm run test && jest-coverage-badges input './coverage/coverage-summary.json' output './badges'",
        "test-update": "jest --updateSnapshot",
        "lint:css": "stylelint './src/**/*.js'",
        "storybook": "start-storybook -p 6006",
        "build-storybook": "build-storybook -c .storybook -o .out",
        "generate": "plop --plopfile ./.plop/plop.config.js",
        "build": "webpack --mode production",
        "prepare": "npm run build",
        "prepublishOnly": "npm run test:badges",
        "storybook-docs": "build-storybook --docs",
        "todo": "leasot './src/**/*.js'",
        "todo-ci": "leasot -x --reporter markdown './src/**/*.js' > TODO.md"
    },
    "license": "ISC",
    "peerDependencies": {
        "prop-types": "^15.7.2",
        "react": "^16.9.0",
        "react-dom": "^16.9.0",
        "recharts": "^1.7.1",
        "styled-components": "^4.3.2",
        "styled-normalize": "^8.0.6"
    },
    "devDependencies": {
        "@babel/cli": "^7.6.0",
        "@babel/core": "^7.6.0",
        "@babel/plugin-proposal-class-properties": "^7.5.5",
        "@babel/preset-env": "^7.6.0",
        "@babel/preset-react": "^7.0.0",
        "@storybook/addon-actions": "^5.2.1",
        "@storybook/addon-docs": "^5.2.1",
        "@storybook/addon-info": "^5.2.1",
        "@storybook/addon-knobs": "^5.2.1",
        "@storybook/addon-links": "^5.2.1",
        "@storybook/addon-viewport": "^5.2.1",
        "@storybook/addons": "^5.2.1",
        "@storybook/react": "^5.2.1",
        "babel-eslint": "^10.0.3",
        "babel-jest": "^24.9.0",
        "babel-loader": "^8.0.6",
        "babel-plugin-styled-components": "^1.10.6",
        "eslint": "^6.5.1",
        "eslint-plugin-react": "^7.15.0",
        "eslint-plugin-react-hooks": "^2.1.1",
        "jest": "^24.9.0",
        "jest-coverage-badges": "^1.1.2",
        "jest-styled-components": "^6.3.3",
        "leasot": "^8.2.0",
        "plop": "^2.4.0",
        "polished": "^3.4.1",
        "prop-types": "^15.7.2",
        "react": "^16.9.0",
        "react-dom": "^16.9.0",
        "react-test-renderer": "^16.9.0",
        "recharts": "^1.7.1",
        "storybook-styled-components": "github:merishas/storybook-styled-components",
        "styled-components": "^4.4.0",
        "styled-normalize": "^8.0.6",
        "stylelint": "^10.1.0",
        "stylelint-config-recommended": "^2.2.0",
        "stylelint-config-styled-components": "^0.1.1",
        "stylelint-processor-styled-components": "^1.8.0",
        "webpack": "^4.40.2",
        "webpack-cli": "^3.3.9"
    },
    "files": [
        "dist"
    ],
}

The UI Kit's webpack.config.js

const path = require('path');

module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        path: path.resolve('dist'),
        filename: 'index.js',
        libraryTarget: 'commonjs2',
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                exclude: /(node_modules)/,
                use: 'babel-loader',
            },
            {
                test: /\.(eot|svg|ttf|woff|woff2|otf)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]',
                            limit: 10000,
                            mimetype: 'application/font-woff',
                        },
                    },
                ],
            },
        ],
    },
    resolve: {
        alias: {
            components: path.resolve(__dirname, 'src/components/'),
            utils: path.resolve(__dirname, 'src/utils/'),
            themes: path.resolve(__dirname, 'src/themes/'),
        },
        extensions: ['.js', '.jsx'],
    },
    devtool: false,
};

How components are imported and implemented in project:

import React from "react";
import logo from "./logo.svg";
import "./App.css";
import { FieldLabel, Button } from "react-ui-kit";

function App() {
  return (
    <div className="App">
      <FieldLabel>THIS IS THE ONE USING the useRef Hook</FieldLabel>
      <Button>This component is totally fine without FieldLabel, this isn't using Hooks</Button>
    </div>
  );
}

export default App;
like image 231
Morgan Yu Avatar asked Oct 16 '22 10:10

Morgan Yu


1 Answers

Looking at the webpack config, I could see that, UI kit is getting bundled with react included which might be causing the issue.

To avoid this you could use webpack externals.

https://webpack.js.org/configuration/externals/

The externals configuration option provides a way of excluding dependencies from the output bundles. Instead, the created bundle relies on that dependency to be present in the consumer's environment. This feature is typically most useful to library developers, however there are a variety of applications for it.

So you could update UI Kit webpack config to not include react and the peerDependencies should take care of the dependency handling for any consumers of the library.

Updated webpack.config

const path = require("path");
module.exports = {
  mode: "production",
  entry: "./src/index.js",
  output: {
    path: path.resolve("dist"),
    filename: "index.js",
    libraryTarget: "commonjs2"
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /(node_modules)/,
        use: "babel-loader"
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2|otf)$/,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[name].[ext]",
              limit: 10000,
              mimetype: "application/font-woff"
            }
          }
        ]
      }
    ]
  },
  resolve: {
    alias: {
      components: path.resolve(__dirname, "src/components/"),
      utils: path.resolve(__dirname, "src/utils/"),
      themes: path.resolve(__dirname, "src/themes/")
    },
    extensions: [".js", ".jsx"]
  },
  externals: {
        // Use external version of React
        react: "react"
 },
  devtool: false
};

I have published a test package to confirm this (react-ui-kit-dontuse).

Demo links

v0.0.21(Without webpack externals) 

https://stackblitz.com/edit/react-xyjgep

v0.0.23(With webpack externals) 

https://stackblitz.com/edit/react-ihnmrl

Source code of test package: https://github.com/nithinthampi/react-ui-lib-test

Hope this helps!

like image 166
Nithin Thampi Avatar answered Oct 20 '22 00:10

Nithin Thampi