我正在尝试编写一个包含一些 React
内容的 NPM 包,目前它只是一个组件和一个钩子。为了构建包,我正在使用 Webpack。我已将 react
和 react-dom
添加到 externals 部分以确保它不包含在包中。我还在 react
中将 peerDependency
标记为 package.json
并将其包含为 devDependency
。尝试在另一个项目中使用捆绑包时,我仍然收到错误 Invalid hook call
。我想我已经尝试了所有可以通过 Google 搜索的方法(例如使用 package 来解决这个问题),但都没有成功。
我的 Webpack 配置目前如下所示:
const path = require('path');
const isProduction = process.env.NODE_ENV?.toLowerCase() === 'production';
const config = {
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
libraryTarget: 'umd',
},
plugins: [],
module: {
rules: [
{
test: /\.(tsx?)$/i,
loader: 'ts-loader',
exclude: ['/node_modules/'],
},
{
test: /\.(graphql|gql)$/,
exclude: /node_modules/,
loader: 'graphql-tag/loader',
},
],
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.graphql', '.json'],
},
externals: {
react: 'react',
'react-dom': 'react-dom',
},
};
module.exports = () => {
if (isProduction) {
config.mode = 'production';
} else {
config.mode = 'development';
}
return config;
};
package.json
中的要点如下所示:
{
...
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
...
"scripts": {
...
"build": "webpack --mode=production --node-env=production",
"build:dev": "webpack --mode=development",
...
"prepublishOnly": "npm run build"
},
...
"peerDependencies": {
"react": "16.8.0 || ^17.0.2"
},
"peerDependenciesMeta": {
"react": {
"optional": true
}
},
"dependencies": {
"@apollo/client": "^3.3.19",
"apollo-server-errors": "^2.5.0",
"joi": "^17.4.0",
"lodash": "^4.17.21"
},
"devDependencies": {
...
"react": "^17.0.2",
"react-dom": "^17.0.2",
...
}
}
钩子非常简单,它只是尝试使用 useContext
创建的组件的上下文,以确保此逻辑没有问题我尝试仅使用 {{1}具有相同的结果。钩子看起来有点像这样:
setState
function useClient(): Client {
return useContext(getContext());
}
只是一个创建或重用现有 getContext
的函数(深受 Apollo Client 的启发):
React.Context
我尝试使用钩子的组件是一个简单的功能组件:
const cache = new (canUseWeakMap ? WeakMap : Map)<
typeof createContext,
Context<Client | undefined>
>();
function getContext() {
let context = cache.get(createContext);
if (!context) {
context = createContext<Client | undefined>(undefined);
context.displayName = 'ClientContext';
cache.set(createContext, context);
}
return context;
}
export default getContext;
我错过了什么?非常感谢您的帮助!
编辑:
我在一个仅包含基础知识的小型示例应用中重现了该问题,使用 const HelloWorld: FC<HelloWorldProps> = () => {
const client = useClient();
return (
<div>Hello World!</div>
);
};
的外部包,然后在 setState
中使用该包,结果相同:
答案 0 :(得分:0)
感谢大家的帮助!
问题是我停止发布包,而是使用 file:../Client
在本地安装依赖项。这导致了 React
的重复实例,因为它使用了 React
的本地到客户端包实例。仅发布构建的输出然后安装该依赖项为我解决了这个问题。
如果其他人偶然发现这一点,我发现以下 answer 有助于我意识到这一点(链接两个包之间的反应依赖项)。