反应包,无效的钩子调用

时间:2021-05-30 07:15:20

标签: reactjs typescript webpack react-hooks

我正在尝试编写一个包含一些 React 内容的 NPM 包,目前它只是一个组件和一个钩子。为了构建包,我正在使用 Webpack。我已将 reactreact-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 中使用该包,结果相同:

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

1 个答案:

答案 0 :(得分:0)

感谢大家的帮助!

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

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