npm-link库上无效的hook调用。

15

问题描述:

  • I'm currently authoring a package called eformless

  • I've used CRA to create a directory called sandbox, where I linked the package.

  • I keep getting the following error, when trying to launch the sandbox react app with the linked package that I'm trying to test:

    // inside my 'sandbox' App.tsx
    import React from 'react'
    import { useField } from 'eformless'
    
    const App = () => {
      const [test, handleChange] = useField('testing')
      return (
        <input type="text" value={test.value} onChange={handleChange} />
      )
    }
    
错误:无效的钩子调用。Hooks只能在函数组件的主体内调用。这可能是以下原因之一:
1.您可能有不匹配的React和渲染器(例如React DOM)版本 2.您可能正在违反Hooks规则 3.您可能在同一个应用程序中有多个React副本
请参见由于stackoverflow ToS而更改的链接,了解如何调试和解决此问题。
发生问题的位置:
问题似乎指向我的库,在那里我编写了一个使用从React导入的hooks的自定义hook。 以下是代码中有问题的摘录:
export const useField = <T>(
  input: T
  ...checkFunctions: Array<(...args: unknown[]) => unknown>
): [FieldType<T>, FieldHandlerFunction<T>, FieldHandlerFunction<T>] => {
  const [value, setValue] = useState(input)
  const [name, setName] = useState('')
  // Issue seems to be here ^
}

我的设置相当正常,在其他项目中似乎运行良好:

  • 首先通过rollup -c捆绑我的库
  • 通过npm link在我的eformless库文件夹内创建一个链接
  • 并通过npm link eformless在我的sandbox文件夹内创建符号链接

我尝试过的:

我自然而然地尝试通过错误消息中提供的链接来修复问题。如此处所述,这似乎是在链接自己的库时出现的问题。

这个问题也可能出现在使用npm link或其等效物时。在这种情况下,您的打包器可能会“看到”两个React——一个在应用程序文件夹中,一个在您的库文件夹中。假设myapp和mylib是兄弟文件夹,一种可能的解决方法是从mylib运行npm link ../myapp/node_modules/react。这应该使库使用应用程序的React副本。

我确实在我的eformless文件夹中运行了npm link ../sandbox/node_modules/react,但即使在关闭节点服务器和重新编译后,这似乎也没有帮助。

无论如何,这对我来说似乎非常令人困惑,因为运行npm ls react只显示一个版本的react,并且应该是有效的,因为useState在自定义钩子的顶层使用。

重现问题:

两个存储库都是公共的

6个回答

11
  1. 您的应用可能有多个React副本,请参考更改的链接以获取有关如何调试和修复此问题的提示。

这是因为在eformless的devDependencies中有React,这会导致您的应用程序运行两个React实例。

相反,将React移动到eformless的package.json中的对等依赖项中,删除您的node_modules目录并运行npm install

通过将React添加到对等依赖项中,您正在通知模块捆绑器不要包含React,而是期望依赖应用程序提供React。

"peerDependencies": {
  "react": "^16.13.1"
}

另外,我注意到您已经将node_modules目录检入到eformless中。您不应该这样做。相反,应将node_modules添加到您的.gitignore文件中。


是的,我真的很惊讶它是怎么到那里的,因为它应该在我的.gitignore中。至于devDependencies -> peerDependencies,我认为你可能是对的。忘记了这一点,给我一秒钟。 - Samuel Hulla
是的,这确实解决了问题。我只需要添加一个小细节,将我的peerDeps更改为反映钩子所需的最小版本为“ react:“> = 16.8”。 - Samuel Hulla
7
我不确定这是否是合适的解决方案。我有同样的问题,但我在我的开发依赖中使用React是有原因的——用于运行测试。如果按照你的建议将其移除,并仅将React指定为peer dependency,我的测试会失败。 - Patrick Hund
1
说句实话,解决这个问题的方法是在 package.json 文件中添加分辨率配置,具体说明请参见此处:https://github.com/facebook/react/issues/13991#issuecomment-449597362。 - Patrick Hund
分辨率对我没有用,但这个链接有效:https://github.com/facebook/react/issues/13991#issuecomment-435587809 - hairy25

7

如果对他人有用,我已经在我的库中使用react作为“同行依赖项”,但仍然遇到了此问题。

我必须执行以下步骤才能解决它:

在库中

  1. 如果尚未完成,请将生成问题的库设置为package.json中的peerDependencies而非dependenciesdevDependencies,例如在我的情况下是react
"peerDependencies": {
  "react": "^16.8.6",
  ...
}
  1. 运行 npm install
  2. 构建库(在我的情况下,使用 rollup -c npm 脚本进行构建)

在我的主应用程序中:

  1. package.json 中使用相对路径更改我的库的版本,指向我的本地项目,例如:
"dependencies": {
  "my-library": "file:../../libraries/my-library",
  ...
}
  1. resolve.symlinks = false 添加到我的主应用程序的 webpack 配置中。

  2. --preserve-symlinks-main--preserve-symlinks 添加到我的 package.json 启动脚本中,例如:

"scripts": {
  "build": "set WEBPACK_CONFIG_FILE=all&& webpack",
  "start": "set WEBPACK_CONFIG_FILE=all&& webpack && node --preserve-symlinks-main --preserve-symlinks dist/server.js",
}
  1. 运行npm install
  2. 运行npm run start

1
这对我有效,被接受的解决方案则不然。我正在运行webpack dev服务器,而且我不需要node命令。 - Musical Shore
这对我也起作用。虽然我无法执行第6步。 - Lil E
听起来不错,只可惜在我的情况下 create-react-app 中的 esolve.symlinks = false 被抽象化了 :( - fullStackChris

1
另一个选项是在依赖应用程序的构建中使用webpack的alias来去重React依赖项。
在消费链接依赖项的应用程序的webpack.config.js内部:
resolve: {
  alias: {
    react: path.resolve(__dirname, '<app_path>/node_modules/react'),
    'react-dom': path.resolve(__dirname, '<app_path>/node_modules/react-dom')
  }
}

1

如果@Benjamin的答案没有解决问题,那么问题可能是将react和react-dom从dependencies移动到peerDependencies

等一下,还有唯一缺失的步骤:

  1. 删除node_modules并运行npm install --legacy-peer-deps。这不会包括在您的peerDependencies中的react和其他软件包 - 解决了安装多个react的问题。

  2. 现在,您仍然无法运行测试,因为jest找不到这些模块,因为它们未安装在您的库中。您可以做的是将库中的“react导入”映射到主应用程序中安装的react。

  • 在您的主应用程序的jest配置中:
moduleNameMapper: {
    "^react$": "<rootDir>/node_modules/react",
    "^react-dom$": "<rootDir>/node_modules/react-dom",
    ...other packages you have in your peerDependencies
}
  1. 尝试再次运行您的测试,应该可以正常工作。

注意: 如果你已经通过 npm link 链接了你的库的 React,请确保通过执行 npm rm --global react 来撤销它,然后在你的主应用程序中重新安装你的包


1

我也遇到了同样的问题。我的情况与Benjamin所说的类似。清除package.json库中的任何react版本,然后重新安装包。当我将我的react库链接到测试应用程序时,我会得到Cannot read properties of null (reading 'matches')。我通过从测试应用程序链接react-dom然后链接react来解决了这个问题,所以:

从库中:

  • npm link ../myapp/node_modules/react-dom
  • npm link ../myapp/node_modules/react

0

在您的主项目中使用别名。然后对于您的库,它将使用您主项目的别名。

react : path.resolve(__dirname, './node_modules/react')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接