admin管理员组文章数量:1401233
Hi I am trying to create a sample library using React 18.2.0 & Microbundle and Although library built successfully, but when it is consumed in the client app I'm getting the below error in console log:
Library source code
Below is my library code.
App.js
import './App.css';
import Dropdown from "./ponents/Dropdown";
function App() {
let dropdown_data = ['Item 1', 'Item 2', 'Item 3'];
return (
<div className="dropdown">
<Dropdown jsonData={dropdown_data} />
</div>
)
}
export default App;
src/ponents/Dropdown.js
import React from "react";
import {useEffect, useState} from 'react';
export const Dropdown = (props) => {
const [dropdown, setDropdown] = useState([]);
useEffect(() => {
loadData();
}, []);
const loadData = () => {
setDropdown(props.jsonData);
}
return (
<div className="dropdown">
<select> {
dropdown.map((item, index) => (
<option key={index}>
{item}</option>
))
} </select>
</div>
)
}
src/lib.package.js
export { Dropdown } from "./ponents/Dropdown.js";
package.json
{
"name": "libtestone",
"version": "0.1.0",
"private": true,
"main": "./dist/lib.umd.js",
"module": "./dist/lib.module.js",
"source": "src/lib.package.js",
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build:lib": "microbundle --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react"
},
"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"
]
},
"devDependencies": {
"microbundle": "^0.15.0"
}
}
Client application source code
This is where I am consuming the package.
App.js
import './App.css';
import {Dropdown} from "libtestone";
function App() {
return (
<div>
<Dropdown />
</div>
);
}
export default App;
Hi I am trying to create a sample library using React 18.2.0 & Microbundle and Although library built successfully, but when it is consumed in the client app I'm getting the below error in console log:
Library source code
Below is my library code.
App.js
import './App.css';
import Dropdown from "./ponents/Dropdown";
function App() {
let dropdown_data = ['Item 1', 'Item 2', 'Item 3'];
return (
<div className="dropdown">
<Dropdown jsonData={dropdown_data} />
</div>
)
}
export default App;
src/ponents/Dropdown.js
import React from "react";
import {useEffect, useState} from 'react';
export const Dropdown = (props) => {
const [dropdown, setDropdown] = useState([]);
useEffect(() => {
loadData();
}, []);
const loadData = () => {
setDropdown(props.jsonData);
}
return (
<div className="dropdown">
<select> {
dropdown.map((item, index) => (
<option key={index}>
{item}</option>
))
} </select>
</div>
)
}
src/lib.package.js
export { Dropdown } from "./ponents/Dropdown.js";
package.json
{
"name": "libtestone",
"version": "0.1.0",
"private": true,
"main": "./dist/lib.umd.js",
"module": "./dist/lib.module.js",
"source": "src/lib.package.js",
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build:lib": "microbundle --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react"
},
"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"
]
},
"devDependencies": {
"microbundle": "^0.15.0"
}
}
Client application source code
This is where I am consuming the package.
App.js
import './App.css';
import {Dropdown} from "libtestone";
function App() {
return (
<div>
<Dropdown />
</div>
);
}
export default App;
Share
Improve this question
edited Jul 14, 2022 at 0:18
Sergey Vyacheslavovich Brunov
18.1k7 gold badges52 silver badges85 bronze badges
asked Jul 11, 2022 at 16:52
MadpopMadpop
7254 gold badges29 silver badges63 bronze badges
20
- I remember having a similar problem when using Webpack's Module Federation, it turned to be that there was multiple instances of React. – Camilo Commented Jul 13, 2022 at 18:51
-
List
react
andreact-dom
aspeerDependencies
. – morganney Commented Jul 14, 2022 at 0:26 - @Camilo How did u resolve it ? – Madpop Commented Jul 14, 2022 at 1:50
- @morganney where in the plugin ? – Madpop Commented Jul 14, 2022 at 1:51
- 1 @SergeyVyacheslavovichBrunov No Via Local file system only npm i file:../libtestone and below is my repo github./Devsnapper/reac-lib – Madpop Commented Jul 14, 2022 at 2:48
4 Answers
Reset to default 4You should probably put react
, react-dom
and react-scripts
in peerDependencies
so that they don't get bundled along with your library. That could be the reason you're facing this issue, since putting react
in dependencies
might create two instances of React.
Edit: The real culprit was the usage of npm i file:../libone
.
Apparently this is an issue where it won't happen if you publish your library, because if react
and react-dom
are in peerDependencies
, it will use the local instance of React.
However in your case, you have a library folder adjacent to a client app folder, and whenever you import your ponent from the library it's using its own instance of React from its node_modules
, which is causing the errors.
In order to solve this, make sure to have the following:
In libone:
package.json
:"devDependencies": { "microbundle": "^0.15.0" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^13.5.0", "react": "file:../userone/node_modules/react", "react-dom": "file:../userone/node_modules/react-dom", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }
Also change build:lib
to this (not sure if it has a big impact but that's the setup I had):
"build:lib": "microbundle build --globals react=React,react-dom=ReactDOM --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react"
In userone:
package.json
:"dependencies": { "libone": "file:../libone", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }
Make sure to remove both node_modules
, run npm install
in userone, then npm install
in libone, then remove dist
folder from libone and run npm run build:lib
.
Notice that in libone package.json
we're referencing the react
and react-dom
that are installed inside your userone folder, and that solves the problem of two React instances when using npm i file:../libone
.
libone
- Your library (
libone/
) must not have a hard dependency onreact
; a peer dependency is enough. (If you'd like it to have a self-contained demo app, then things are slightly different and I might remend Vite's library mode like I've recently done here instead ofmicrobundle
). - The library should not depend on
react-scripts
in any way; it doesn't need to.
All in all, this package.json
does the trick (the script being named prepare
so the dist/
files get built at a correct time; naturally you could still use build:lib
, but then your prepare
script must call it with e.g. npm run build:lib
):
{
"name": "libone",
"version": "0.1.0",
"private": true,
"source": "lib/index.js",
"main": "./dist/lib.umd.js",
"module": "./dist/lib.module.js",
"peerDependencies": {
"react": "^18.2.0"
},
"scripts": {
"prepare": "microbundle build --globals react=React,react-dom=ReactDOM --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react"
},
"devDependencies": {
"microbundle": "^0.15.0"
}
}
userone
- The client application
userone
can usereact-scripts
,vite
, or whatever way you like to build a React app. - The client application's
dependencies
should contain React, ReactDOM, etc.
With a layout that has libone/
and userone/
as siblings, using react-scripts, userone
's package.json could be something like
{
"name": "userone",
"version": "0.1.0",
"private": true,
"dependencies": {
"libone": "../libone",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test"
}
}
In addition, if you use npm link
or yarn link
for libone
, it's imperative that libone
's node_modules/
directory does not contain React; that will confuse Webpack.
It looks like there are multiple copies of React in the same bundle.
So there are some possible ways to solve this error:
Try to publish your package to NPM and then import it directly from NPM.
A (hacky) workaround at the moment using npm-link-shared and a prestart npm script to essentially replace the one package's react dependency with a symlink to the other's, so they use the same instance.
"prestart": "npm-link-shared ./node_modules/<other package>/node_modules . react"
It can be resolved by adding:
alias: { react: path.resolve('./node_modules/react') }
to resolve property in webpack config of my main app.
Alternative solution:
As React docs says:
In order for Hooks to work, the react import from your application code needs to resolve to the same module as the react import from inside the react-dom package.
If these react imports resolve to two different exports objects, you will see this warning. This may happen if you accidentally end up with two copies of the react package.
So it looks like you need to check the above statement as you are developing separate library. How can is it possible to check? It is possible to check by:
The First Way:
If you use Node for package management, you can run this check in your project folder:
npm ls react
If you see more than one React, you’ll need to figure out why this happens and fix your dependency tree. For example, maybe a library you’re using incorrectly specifies react as a dependency (rather than a peer dependency). Until that library is fixed, Yarn resolutions is one possible workaround.
The second way:
You can also try to debug this problem by adding some logs and restarting your development server:
// Add this in node_modules/react-dom/index.js
window.React1 = require('react');
// Add this in your ponent file
require('react-dom');
window.React2 = require('react');
console.log(window.React1 === window.React2);
If it prints false then you might have two Reacts and need to figure out why that happened. This issue includes some mon reasons encountered by the munity.
Introduction
Let's consider the following versions as the current versions:
- npm:
8.13.2
.
Let's consider the article that describes the same problem: Invalid Hook Call Warning – React.
Changes to get reproducible example
Client application (apptestone
)
Since the provided (posted right in the question, not on GitHub) source code of the client application is not plete, I have created an example client application with Create React App:
/question-72942020/src$ npx create-react-app apptestone
package.json
{
"name": "apptestone",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "5.16.4",
"@testing-library/react": "13.3.0",
"@testing-library/user-event": "13.5.0",
"libtestone": "file:../libtestone",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"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"
]
}
}
Resulting directory structure
/question-72942020/src$ tree --charset unicode -L 2
.
|-- apptestone
| |-- build
| |-- node_modules
| |-- package.json
| |-- package-lock.json
| |-- public
| |-- README.md
| `-- src
`-- libtestone
|-- dist
|-- node_modules
|-- package.json
|-- package-lock.json
`-- src
General changes
Library package (libtestone/package.json
): Reduce scope of dependencies
Update the file as follows:
"dependencies": {
},
<…>
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
<…>
"devDependencies": {
"microbundle": "^0.15.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
Run the mand:
/question-72942020/src/libtestone$ npm clean-install
Library ponent (libtestone/src/ponents/Dropdown.js
): Use «fallback» value
Update the function as follows:
const loadData = () => {
setDropdown(props.jsonData || ["Loaded data"]);
};
This will allow using the Dropdown
ponent like it is shown in your example:
function App() {
return (
<div>
<Dropdown />
</div>
);
}
Analysis
After making the changes described in the «Changes to get reproducible example» and «General changes» sections:
- The problem has been reproduced.
- The analysis has been started.
It is an important detail that you have installed the library package into the application package from a local file system (not from an npm registry).
It seems that had you installed the library from an npm registry, the changes described in the «General changes» section would be sufficient to solve the problem or would not be necessary at all.
It seems that the «Duplicate React» problem takes place according to the symptom (the output):
/question-72942020/src/apptestone$ npm ls react
[email protected] /question-72942020/src/apptestone
├─┬ @testing-library/[email protected]
│ └── [email protected] deduped
├─┬ [email protected] -> ./../libtestone
│ ├─┬ @testing-library/[email protected]
│ │ └── [email protected] deduped
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ └── [email protected] <!-- NOTE!
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
└── [email protected] <!-- NOTE!
Please, note the <!-- NOTE!
markers.
The article states:
This problem can also e up when you use
npm link
or an equivalent. In that case, your bundler might “see” two Reacts — one in application folder and one in your library folder.
Possible solution
The article describes a possible solution:
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.
Let's adapt the solution to the current case.
The resulting mand:
/question-72942020/src/libtestone$ npm link ../apptestone/node_modules/react ../apptestone/node_modules/react-dom
Please, note the working directory path (before $
).
Let's check the created symbolic links:
/question-72942020/src/libtestone$ ls -la node_modules/react{,-dom}
<…> node_modules/react -> ../../apptestone/node_modules/react
<…> node_modules/react-dom -> ../../apptestone/node_modules/react-dom
Let's check the duplication:
/question-72942020/src/apptestone$ npm ls react
[email protected] /question-72942020/src/apptestone
├─┬ @testing-library/[email protected]
│ └── [email protected] deduped
├─┬ [email protected] -> ./../libtestone
│ ├─┬ @testing-library/[email protected]
│ │ └── [email protected] deduped -> ./node_modules/react
│ ├─┬ [email protected]
│ │ └── [email protected] deduped -> ./node_modules/react
│ ├─┬ [email protected]
│ │ └── [email protected] deduped -> ./node_modules/react
│ └── [email protected] -> ./node_modules/react <!-- NOTE!
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
└── [email protected] <!-- NOTE!
Please, note the <!-- NOTE!
markers.
This is it.
Development workflow
Now it is possible to work on the library: make a change, build it (npm run build:lib
).
Given that the application is started in the development mode (npm start
), the library changes will be taken into account (upon library rebuild: npm run build:lib
).
Caveat
It seems that every time a package installation npm mand (npm install
, etc.) is performed for the library project, the npm links will be reverted to module directories.
It is necessary to recreate them.
本文标签:
版权声明:本文标题:javascript - Unable to render useState, useEffect hooks in custom component package using microbundle & React - Stack Ov 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744249639a2597188.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论