I've been trying to create my own Component Library for the past few weeks, everything is going smooth except from the fact that I can't get hooks to work. Whenever I import from the library a component that uses hooks I get "Hooks can only be called inside the body of a function component."
https://reactjs.org/warnings/invalid-hook-call-warning.html
I would expect it's something about React being duplicated which I don't see when I run npm ls react
.
This is my webpack.config.js
const path = require('path');
var nodeExternals = require('webpack-node-externals');
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
},
{
test: /\.scss$/,
sideEffects: true,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},
{
test: /\.(png|gif|jpg|svg)$/,
use: {
loader: 'url-loader',
options: {
limit: 50000,
},
},
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
]
}
],
},
resolve: {
extensions: ['.scss', '.ttf', '.js', '.json', '.png', '.gif', '.jpg', '.svg'],
},
output: {
path: path.resolve(__dirname, 'dist/'),
publicPath: '',
filename: 'index.js',
libraryTarget: 'umd',
},
target: 'node',
externals: [ nodeExternals() ]
};
This is my package-json
{
"name": "ui-components",
"version": "1.1.1",
"description": "componentes UI",
"main": "dist/index.js",
"scripts": {
"test": "jest",
"build": "webpack --mode production",
"storybook": "start-storybook -p 9001",
"docz:dev": "docz dev",
"docz:build": "docz build"
},
"repository": {
"type": "git",
"url": "..."
},
"keywords": [
"react",
"shared",
"components",
"botbit"
],
"author": "Uriel Chami",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.2.3",
"@babel/preset-react": "^7.0.0",
"@storybook/addon-actions": "^5.0.0",
"@storybook/addon-storyshots": "^5.1.10",
"@storybook/react": "^5.0.0",
"@tulipjs/eslint-config": "^1.1.1",
"babel-loader": "^8.0.1",
"babel-plugin-macros": "^2.6.1",
"css-loader": "^1.0.0",
"docz": "^1.2.0",
"docz-theme-default": "^1.2.0",
"file-loader": "^4.1.0",
"jest": "^24.8.0",
"node-sass": "^4.9.3",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-router-dom": "^5.0.1",
"react-test-renderer": "^16.8.6",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"url-loader": "^1.1.2",
"webpack": "^4.28.3",
"webpack-cli": "^3.2.0",
"webpack-node-externals": "^1.7.2"
},
"peerDependencies": {
"react": "16.9.0",
"react-dom": "16.9.0"
},
"dependencies": {
"mdbreact": "..."
}
}
Im using npm link
to test the functioning of the library but also I can deploy it to GitHub and npm update
it.
I've added window.React1 = require('react');
in node_modules/react-dom/index.js (in the App that uses my library).
And
require('react-dom');
window.React2 = require('react');
console.log(window.React1);
console.log(window.React1 === window.React2);
in my App.js (in the app that uses my library).
And it throws true
. I'm slowly getting clueless. Any ideas?
Edit:
The code where I'm trying to use Hooks is:
import React, {useEffect} from 'react';
export const Test = () => {
useEffect(()=>{
console.log("component did mount");
} , [])
return(<div>Hola!</div>);
}
Edit 2
When I build yarn webpack --mode development
it throws 'require is not defined'.
Here it goes a GitHub repo with my complete code if anyone wants to toy around: https://github.com/uchami/hooks-not-working
Edit 3
I add the component library (ui-components) as so yarn add git+ssh:repository
.
The application where I import my library is simply a plain create-react-app.
And I just implement the Test
component (which is the one that uses Hooks) using import {Test} from 'ui-components'
and I use it just like that <Test></Test>
.
The compilation of the ui-components
project is just yarn build
on the console. On the background what is doing is calling yarn webpack --mode production
. If you call yarn webpack --mode development
you will see extra verbose error output.
Let's rule out all possibilities according to React docs:
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.
1.) If unsure, try to reinstall react
and react-dom
in the latest version in your app, so they 100% match (or look at your package-lock.json
/ yarn lock):
npm i react@latest react-dom@latest
2.) Your useEffect
Hook usage inside Test
looks fine - Test
is a function component and useEffect
is called at the top-level.
3.) It would be my main guess for the error at hand.
You are using npm link
to link the library for local tests. npm link
will add a symbolic link for the complete library working directory (including node_modules
) inside app project's node_modules
. react
is installed both as devDependencies
in the library and as dependencies
in the app project.
Now, when Webpack bundles the app project, it will choose react
either from library or app - whichever is included in the nearest node_modules
folder relative to the importing module.
A fix is mentioned on the Invalid Hook Call Warning page:
Assuming
myapp
andmylib
are sibling folders, one possible fix is to runnpm link ../myapp/node_modules/react
frommylib
. This should make the library use the application’s React copy.
Alternative: Tell Webpack to always resolve to a single react
package - the one in your app node_modules
(credit goes to these two issues). webpack.config.js
:
resolve: {
...
alias: {
// Needed when library is linked via `npm link` to app
react: path.resolve("./node_modules/react")
}
}
This likely happens, when you run the web app bundled by a faulty Webpack config, where require
calls are not dropped and replaced by the actual code modules.
If the application project is based on create-react-app
, you might import the library in app and just run start or build. Given a custom Webpack config (e.g. via eject
), run the build with target:web
(or omit target
) and leave out externals: [ nodeExternals() ]
.
Is it just that you're trying to use your library in React apps running older versions of React that aren't compatible with hooks?
I just made a new create-react-app, added your repo as a dependency with yarn add https://github.com/uchami/hooks-not-working
, and had no problem adding the Test component to the default App.js
.
I only got an error after rolling back my app's version of React.
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