<p dir="auto"><strong>Do you want to request a <em>feature</em> or report a <em>bug</em>?</strong><br>
bug</p>
<p dir="auto"><strong>What is the current behavior?</strong><br>
We are trying to create an external module which will be imported in main app.<br>
Here is the module :</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="export const MyHelloComponent = (props) =&gt; {
  const [test, setTest] = useState();
  return (&lt;div&gt;Hello&lt;/div&gt;);
}"><pre lang="import" class="notranslate"><code class="notranslate">export const MyHelloComponent = (props) =&gt; {
  const [test, setTest] = useState();
  return (&lt;div&gt;Hello&lt;/div&gt;);
}
</code></pre></div>
<p dir="auto">Importing this simple code into main app gives us the error :</p>
<blockquote>
<p dir="auto">Uncaught Invariant Violation: Hooks can only be called inside the body of a function component</p>
</blockquote>
<p dir="auto">Removing hooks this code works fine.</p>
<p dir="auto">We have followed instructions from <a href="https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react" rel="nofollow">https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react</a> but error still thrown</p>
<p dir="auto">If we link react as mentionned in documentation, works but it only can be done in development not in production.</p>
<p dir="auto">We are not the only one having this issue <a href="https://stackoverflow.com/questions/54916349/side-package-with-react-hooks-failing-with-invariant-violation-when-called-in" rel="nofollow">Side package with React Hooks failing with Invariant Violation when called in main package</a></p>
<p dir="auto"><strong>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 (<a href="https://jsfiddle.net/Luktwrdm/" rel="nofollow">https://jsfiddle.net/Luktwrdm/</a>) or CodeSandbox (<a href="https://codesandbox.io/s/new" rel="nofollow">https://codesandbox.io/s/new</a>) example below:</strong></p>
<p dir="auto"><strong>Code from external component :</strong><br>
package.json</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{
  &quot;name&quot;: &quot;app-component&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;main&quot;: &quot;build/index.js&quot;,
  &quot;license&quot;: &quot;MIT&quot;,
  &quot;private&quot;: true,
  &quot;peerDependencies&quot;: {
    &quot;react&quot;: &quot;^16.8.4&quot;,
    &quot;react-dom&quot;: &quot;^16.8.4&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.3.4&quot;,
    &quot;@babel/plugin-proposal-class-properties&quot;: &quot;^7.3.4&quot;,
    &quot;@babel/plugin-proposal-object-rest-spread&quot;: &quot;^7.3.4&quot;,
    &quot;@babel/plugin-transform-react-jsx&quot;: &quot;^7.3.0&quot;,
    &quot;@babel/plugin-transform-regenerator&quot;: &quot;^7.3.4&quot;,
    &quot;@babel/preset-env&quot;: &quot;^7.3.4&quot;,
    &quot;@babel/preset-react&quot;: &quot;^7.0.0&quot;,
    &quot;babel-loader&quot;: &quot;^8.0.5&quot;,
    &quot;css-loader&quot;: &quot;^2.1.0&quot;,
    &quot;react&quot;: &quot;^16.8.4&quot;,
    &quot;react-dom&quot;: &quot;^16.8.4&quot;,
    &quot;style-loader&quot;: &quot;^0.23.1&quot;,
    &quot;styled-jsx&quot;: &quot;^3.2.1&quot;,
    &quot;webpack&quot;: &quot;^4.29.5&quot;,
    &quot;webpack-cli&quot;: &quot;^3.2.3&quot;
  },
  &quot;scripts&quot;: {
    &quot;build&quot;: &quot;./node_modules/.bin/webpack --mode production&quot;,
    &quot;dev&quot;: &quot;./node_modules/.bin/webpack --mode development --watch&quot;
  },
  &quot;files&quot;: [
    &quot;build&quot;
  ],
  &quot;dependencies&quot;: {
    &quot;@material-ui/core&quot;: &quot;^3.9.2&quot;
  }
}"><pre class="notranslate"><code class="notranslate">{
  "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"
  }
}
</code></pre></div>
<p dir="auto">webpack.config.js</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="const path = require('path');
const pkg = require('./package.json');

const libraryName= pkg.name;

module.exports = (env, argv) =&gt; ({
  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: &quot;react&quot;,
    &quot;react-dom&quot;: &quot;react-dom&quot;
  }
});"><pre class="notranslate"><code class="notranslate">const path = require('path');
const pkg = require('./package.json');

const libraryName= pkg.name;

module.exports = (env, argv) =&gt; ({
  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"
  }
});
</code></pre></div>
<p dir="auto">src/index.js</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="export * from './components/hello';"><pre class="notranslate"><code class="notranslate">export * from './components/hello';
</code></pre></div>
<p dir="auto">src/components/hello.js</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import React, { useState } from 'react';
export const MyHelloComponent = (props) =&gt; {
  const [test, setTest] = useState();
  return (&lt;div&gt;Hello&lt;/div&gt;);
}"><pre class="notranslate"><code class="notranslate">import React, { useState } from 'react';
export const MyHelloComponent = (props) =&gt; {
  const [test, setTest] = useState();
  return (&lt;div&gt;Hello&lt;/div&gt;);
}
</code></pre></div>
<p dir="auto"><strong>Code from main app:</strong><br>
webpack.config.js</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="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']
      }
    ]
  },
};"><pre class="notranslate"><code class="notranslate">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']
      }
    ]
  },
};
</code></pre></div>
<p dir="auto">package.json</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{
  &quot;name&quot;: &quot;react-app-shell&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;license&quot;: &quot;MIT&quot;,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;webpack-dev-server --mode development&quot;
  },
  &quot;dependencies&quot;: {
    &quot;react&quot;: &quot;^16.8.4&quot;,
    &quot;react-dom&quot;: &quot;^16.8.4&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;@babel/core&quot;: &quot;^7.3.4&quot;,
    &quot;@babel/preset-env&quot;: &quot;^7.3.4&quot;,
    &quot;@babel/preset-react&quot;: &quot;^7.0.0&quot;,
    &quot;babel-loader&quot;: &quot;^8.0.5&quot;,
    &quot;webpack&quot;: &quot;^4.29.6&quot;,
    &quot;webpack-cli&quot;: &quot;^3.2.3&quot;,
    &quot;webpack-dev-server&quot;: &quot;^3.2.1&quot;
  }
}"><pre class="notranslate"><code class="notranslate">{
  "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"
  }
}
</code></pre></div>
<p dir="auto">src/index.js</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import React from &quot;react&quot;;
import ReactDOM from &quot;react-dom&quot;;
import {MyHelloComponent} from 'app-component';

class Welcome extends React.Component {
  render() {
    return &lt;&gt;&lt;h1&gt;Main App&lt;/h1&gt;&lt;MyHelloComponent/&gt;&lt;/&gt;;
  }
}
ReactDOM.render(&lt;Welcome /&gt;, document.getElementById(&quot;root&quot;));"><pre class="notranslate"><code class="notranslate">import React from "react";
import ReactDOM from "react-dom";
import {MyHelloComponent} from 'app-component';

class Welcome extends React.Component {
  render() {
    return &lt;&gt;&lt;h1&gt;Main App&lt;/h1&gt;&lt;MyHelloComponent/&gt;&lt;/&gt;;
  }
}
ReactDOM.render(&lt;Welcome /&gt;, document.getElementById("root"));
</code></pre></div>
<p dir="auto">To be able to make it works, you have to do <code class="notranslate">yarn link</code> after (or before) having built it  from component and <code class="notranslate">yarn link "app-component"</code> from main app.</p>
<p dir="auto"><strong>What is the expected behavior?</strong><br>
use hooks from external components works obviously.</p>
<p dir="auto"><strong>Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?</strong><br>
React 16.8.4 and with previous version it doest not work too</p>
<p dir="auto">I want to save a class instance, not just plain object, with <code class="notranslate">useRef</code> hook. And, I dont want to construct it each time hook function is invoked.</p>
<p dir="auto">Is it possible to do that?</p>
<p dir="auto">My thoughts were:</p>
<div class="highlight highlight-source-js notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="const instanceRef = useRef(() =&gt; new Instance())"><pre class="notranslate"><span class="pl-k">const</span> <span class="pl-s1">instanceRef</span> <span class="pl-c1">=</span> <span class="pl-en">useRef</span><span class="pl-kos">(</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-k">new</span> <span class="pl-v">Instance</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">)</span></pre></div>
<p dir="auto">But <code class="notranslate">useRef</code> does not accept the <em>initial value</em> as a function (<code class="notranslate">useState</code> and <code class="notranslate">useReducer</code> could do that).<br>
Will that change in <em>alpha 3</em>?</p>