Description
Do you want to request a feature or report a bug?
bug
What is the current behavior?
We are trying to create an external module which will be imported in main app.
Here is the module :
export const MyHelloComponent = (props) => {
const [test, setTest] = useState();
return (<div>Hello</div>);
}
Importing this simple code into main app gives us the error :
Uncaught Invariant Violation: Hooks can only be called inside the body of a function component
Removing hooks this code works fine.
We have followed instructions from https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react but error still thrown
If we link react as mentionned in documentation, works but it only can be done in development not in production.
We are not the only one having this issue Side package with React Hooks failing with Invariant Violation when called in main package
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:
Code from external component :
package.json
{
"name": "app-component",
"version": "1.0.0",
"main": "build/index.js",
"license": "MIT",
"private": true,
"peerDependencies": {
"react": "^16.8.4",
"react-dom": "^16.8.4"
},
"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/plugin-proposal-class-properties": "^7.3.4",
"@babel/plugin-proposal-object-rest-spread": "^7.3.4",
"@babel/plugin-transform-react-jsx": "^7.3.0",
"@babel/plugin-transform-regenerator": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.5",
"css-loader": "^2.1.0",
"react": "^16.8.4",
"react-dom": "^16.8.4",
"style-loader": "^0.23.1",
"styled-jsx": "^3.2.1",
"webpack": "^4.29.5",
"webpack-cli": "^3.2.3"
},
"scripts": {
"build": "./node_modules/.bin/webpack --mode production",
"dev": "./node_modules/.bin/webpack --mode development --watch"
},
"files": [
"build"
],
"dependencies": {
"@material-ui/core": "^3.9.2"
}
}
webpack.config.js
const path = require('path');
const pkg = require('./package.json');
const libraryName= pkg.name;
module.exports = (env, argv) => ({
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'index.js',
library: libraryName,
libraryTarget: 'commonjs2',
publicPath: '/build/',
},
devtool: argv.mode !== 'production' ? 'inline-source-map': false,
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
exclude: /(node_modules|bower_components)/,
use: ['babel-loader']
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
]
},
resolve: {
alias: {
'react': path.resolve('./node_modules/react'),
'react-dom': path.resolve('./node_modules/react-dom'),
}
},
externals: {
react: "react",
"react-dom": "react-dom"
}
});
src/index.js
export * from './components/hello';
src/components/hello.js
import React, { useState } from 'react';
export const MyHelloComponent = (props) => {
const [test, setTest] = useState();
return (<div>Hello</div>);
}
Code from main app:
webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
path: __dirname + '/dist',
publicPath: '/dist/',
filename: 'bundle.js'
},
devServer: {
contentBase: './public',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
},
};
package.json
{
"name": "react-app-shell",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "webpack-dev-server --mode development"
},
"dependencies": {
"react": "^16.8.4",
"react-dom": "^16.8.4"
},
"devDependencies": {
"@babel/core": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.5",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.2.1"
}
}
src/index.js
import React from "react";
import ReactDOM from "react-dom";
import {MyHelloComponent} from 'app-component';
class Welcome extends React.Component {
render() {
return <><h1>Main App</h1><MyHelloComponent/></>;
}
}
ReactDOM.render(<Welcome />, document.getElementById("root"));
To be able to make it works, you have to do yarn link
after (or before) having built it from component and yarn link "app-component"
from main app.
What is the expected behavior?
use hooks from external components works obviously.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
React 16.8.4 and with previous version it doest not work too