首页 > 解决方案 > 反应包,无效的钩子调用

问题描述

我正在尝试编写一个包含一些React东西的 NPM 包,目前它只是一个组件和一个钩子。要构建我正在使用 Webpack 的包。我已将reactand添加react-dom到 externals 部分以确保它不包含在捆绑包中。我还在 中标记react为 apeerDependency并将package.json其包含为devDependency. Invalid hook call尝试在另一个项目中使用捆绑包时仍然出现错误。我想我已经尝试了所有可以用谷歌搜索的方法(比如使用来解决这个问题),但没有运气。

我的 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,以确保我尝试使用的这个逻辑没有问题,setState结果相同。钩子看起来有点像这样:

function useClient(): Client {
  return useContext(getContext());
}

getContext只是一个创建或重用现有的函数React.Context(深受 Apollo Client 的启发):

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,然后在 a 中使用该包,create-react-app结果相同:

https://github.com/ganhammar/invalid-hook-call

标签: reactjstypescriptwebpackreact-hooks

解决方案


感谢所有的帮助!

问题是我停止发布包,而是使用file:../Client. 这导致了 的重复实例,React因为它使用了 的本地到客户端包实例React。仅发布构建的输出然后安装该依赖项为我解决了这个问题。

如果其他人偶然发现以下答案,我发现以下答案有助于我意识到这一点(链接两个包之间的反应依赖)。


推荐阅读