react-native 和 yarn 工作区的“钩子只能在函数组件的主体内调用”错误
Posted
技术标签:
【中文标题】react-native 和 yarn 工作区的“钩子只能在函数组件的主体内调用”错误【英文标题】:"Hooks can only be called inside the body of a function component" error with react-native and yarn workspace 【发布时间】:2020-10-19 23:27:02 【问题描述】:我目前正在开发一个基于 yarn 工作区的项目。我整天在 react-native 中正确安装 apollo 时遇到问题,最后,我设法通过更改 metro.config.js 文件的配置来做到这一点(即使我认为它不会影响问题)。但是,当我开始实现@apollo/react-hooks 库时,我遇到了以下错误:
钩子只能在函数组件内部调用。
我在网上冲浪时遇到了其他类似的问题,官方的反应文档说:
There are three common reasons you might be seeing it:
- You might have mismatching versions of React and React DOM.
- You might be breaking the Rules of Hooks.
- You might have more than one copy of React in the same app.
我认为第二个选项被排除在外,因为我实现的代码非常简单,而且我认为不可能出现错误。即使是第一个选项对我来说似乎也是不可能的,因为我使用的是 react-native,因此我没有使用 React DOM 模块(如果我错了,请为我的无知道歉)。
最后一个选项是最受认可的选项。事实上,检查两个 node_modules 文件夹(一个位于工作空间的根目录,一个位于移动应用程序包中),我意识到“react”模块存在于两个目录中。
通过尝试,我意识到只有在 react-native 应用程序的 package.json 文件中使用“nohoist”属性时才会安装两次 react 模块。一旦我将 react-native 模块插入到“nohoist”数组中,react 也会安装在“本地”node_modules 文件夹以及项目根目录中。
"workspaces":
"nohoist": [
"react-native", <---------
"react-native/**", <---------
"@react-native-mapbox-gl",
"@react-native-mapbox-gl/**",
"react-native-gesture-handler",
"react-native-gesture-handler/**",
"react-native-reanimated",
"react-native-reanimated/**",
"@react-navigation",
"@react-navigation/**",
"react-native-safe-area-context",
"react-native-safe-area-context/**",
"react-native-vector-icons",
"react-native-vector-icons/**",
"react-native-pose",
"react-native-pose/**",
"@react-native-community",
"@react-native-community/**",
"react-native-elements",
"react-native-elements/**"
]
我无法理解“react-native”模块如何影响“react”模块。我想这里的解决方案是防止这种情况发生,但我不知道如何。
这是 metro.config.js 文件(如果有人想检查它,即使我认为它与这个问题无关):
const path = require("path");
const getWorkspaces = require("get-yarn-workspaces");
const blacklist = require("metro-config/src/defaults/blacklist");
const workspaces = getWorkspaces(__dirname);
module.exports =
projectRoot: path.resolve(__dirname, "."),
watchFolders: [path.resolve(__dirname, "../../node_modules"), ...workspaces],
resolver:
blacklistRE: blacklist(
workspaces.map(
(workspacePath) =>
`/$workspacePath.replace(
/\//g,
"[/\\\\]",
)[/\\\\]node_modules[/\\\\]react-native[/\\\\].*/`,
),
),
extraNodeModules:
"react-native": path.resolve(__dirname, "node_modules/react-native"),
,
,
;
相反,这是错误来源的文件:
import React, useState from "react";
import View, Text, Button from "react-native";
import StackScreenProps from "@react-navigation/stack";
import AuthStackParamList from "../../../navigation";
import useRegisterMutation from "../../../generated/graphql";
import InputText from "../../../components/InputText";
type SignUpScreenProps = StackScreenProps<AuthStackParamList, "SignUp">;
export const SignUpScreen: React.FC<SignUpScreenProps> = (navigation) =>
const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [signup] = useRegisterMutation();
const handleSubmit = async () =>
const data, errors = await signup(
variables: username, email, password,
);
console.log(data, errors);
;
return (
<View style=flex: 1, justifyContent: "center", alignItems: "center">
<Text>SignUp</Text>
<InputText
label="Username"
value=username
onChangeText=setUsername
textContentType="username"
/>
<InputText
label="Email"
value=email
onChangeText=setEmail
textContentType="emailAddress"
/>
<InputText
label="Email"
value=password
onChangeText=setPassword
textContentType="password"
secureTextEntry
/>
<Button title="Crea account" onPress=handleSubmit />
</View>
);
;
在此先感谢大家。
更新:
通过在工作区根目录的 package.json 中的“nohoist”字段中添加“react”,我已经(目前)解决了该错误。但是,我确信当我将 Web 应用程序 (reactjs) 添加到工作区时,问题会再次出现。因此,如果有人有更好的解决方案,无疑是可以接受的。
"name": "root",
"private": true,
"workspaces":
"packages": [
"packages/*"
],
"nohoist": [
"**/react",
"**/react/**"
]
,
"scripts": ,
"devDependencies":
"lerna": "^3.20.2"
【问题讨论】:
【参考方案1】:你必须这样使用
请导入 useMutation
import useMutation from '@apollo/react-hooks';
这样使用
const [signup] = useMutation(useRegisterMutation)
现在你必须打电话
const handleSubmit = async () =>
const data, errors = await signup(
variables: username, email, password,
);
console.log(data, errors);
;
更多信息请点击Link
【讨论】:
非常感谢您对我的问题的关注,但是,我相信这不是错误的原因。对于我的错误,我忘了写我正在使用一个名为 @graphql-codegen/cli 的包,它会自动为模式中定义的查询生成挂钩。在这种情况下,“useRegisterMutation”函数是从一个文件中导入的,该文件随后会自行生成。我也尝试按照您的方法进行操作,但仍然收到相同的错误。以上是关于react-native 和 yarn 工作区的“钩子只能在函数组件的主体内调用”错误的主要内容,如果未能解决你的问题,请参考以下文章
将 react-native 添加到 monorepo 后,React apollo hooks 失败