使用 React 和 React Native 的 Yarn 工作区

Jav*_*ano 6 javascript reactjs react-native yarn-workspaces react-query

我正在努力创建一个yarn workspace在 React 和 React Native 之间共享代码的方法(一旦完全完成,即将发布博客文章!)。

\n

对我们来说最重要的部分是在两个平台之间共享业务逻辑。在这种情况下我们使用react-query网络请求。

\n

我们为此创建了一个“渲染道具”组件

\n
import { useAllDevices } from "../../queries/devices";\n\nexport interface DeviceListProps {\n    devices: any[];\n    isLoading: boolean,\n    onItemClick?: () => void;\n}\n\nexport interface DeviceItemListProps {\n    name: string;\n    onItemClick?: () => void;\n}\n\nexport const DeviceListContainer = ({ render }: { render: any }) => {\n    const { data, isLoading } = useAllDevices();\n    return (\n        <>\n            {render({ devices: data?.devices, isLoading })}\n        </>\n    )\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在哪里useAllDevices有这样的东西:

\n
export const useAllDevices = () => useQuery(\'useAllDevices\', async () => {\n    const devicesResponse = await get(\'/todos\');\n    return {\n        devices: devicesResponse.data,\n    };\n});\n
Run Code Online (Sandbox Code Playgroud)\n

在网络中,它的工作方式就像一个魅力,但我在移动应用程序中遇到错误。问题似乎出在反应查询本身,因为一旦我这样写:

\n
const queryClient = new QueryClient();\n\nconst App = () => {\n  const isDarkMode = false;\n\n  const backgroundStyle = {\n    backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,\n  };\n\n  return (\n    <QueryClientProvider client={queryClient}>\n      <ThemeProvider theme={THEME}>\n        <SafeAreaView style={backgroundStyle}>\n          <StatusBar barStyle={isDarkMode ? \'light-content\' : \'dark-content\'} />\n          <ScrollView\n            contentInsetAdjustmentBehavior="automatic"\n            style={backgroundStyle}>\n            <Header />\n            <Button styleType="primary">hey</Button>\n          </ScrollView>\n        </SafeAreaView>\n      </ThemeProvider>\n    </QueryClientProvider>\n  );\n};\n
Run Code Online (Sandbox Code Playgroud)\n

我收到这个错误

\n

反应本机错误

\n

React 网页版运行正常,没有任何问题

\n

我的package.json应用程序模块是这样的

\n
{\n  "name": "@sharecode/app",\n  "version": "0.0.1",\n  "private": true,\n  "scripts": {\n    "android": "react-native run-android",\n    "ios": "react-native run-ios",\n    "start": "react-native start",\n    "test": "jest --updateSnapshot",\n    "lint": "eslint . --ext .js,.jsx,.ts,.tsx"\n  },\n  "dependencies": {\n    "react": "17.0.2",\n    "react-native": "0.67.3",\n    "react-native-gesture-handler": "^2.3.0",\n    "styled-components": "^5.3.3"\n  },\n  "devDependencies": {\n    "@babel/core": "^7.12.9",\n    "@babel/runtime": "^7.12.5",\n    "@react-native-community/eslint-config": "^2.0.0",\n    "@sharecode/common": "1.0.0",\n    "@testing-library/jest-native": "^4.0.4",\n    "@testing-library/react-native": "^9.0.0",\n    "@types/jest": "^27.4.1",\n    "@types/react-native": "^0.66.15",\n    "@types/react-test-renderer": "^17.0.1",\n    "@types/styled-components-react-native": "^5.1.3",\n    "@typescript-eslint/eslint-plugin": "^5.7.0",\n    "@typescript-eslint/parser": "^5.7.0",\n    "babel-jest": "^26.6.3",\n    "eslint": "^7.14.0",\n    "get-yarn-workspaces": "^1.0.2",\n    "jest": "^26.6.3",\n    "metro-config": "^0.56.0",\n    "metro-react-native-babel-preset": "^0.66.2",\n    "nock": "^13.2.4",\n    "react-test-renderer": "17.0.2",\n    "ts-jest": "^27.1.3",\n    "typescript": "^4.4.4"\n  },\n  "workspaces": {\n    "nohoist": [\n      "react-native",\n      "react-native/**",\n      "react",\n      "react/**",\n      "react-query",\n      "react-query/**"\n    ]\n  },\n  "resolutions": {\n    "@types/react": "^17"\n  },\n  "jest": {\n    "preset": "react-native",\n    "setupFilesAfterEnv": [\n      "@testing-library/jest-native/extend-expect"\n    ],\n    "moduleFileExtensions": [\n      "ts",\n      "tsx",\n      "js",\n      "jsx",\n      "json",\n      "node"\n    ]\n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

主包

\n
{\n  "name": "@sharecode/common",\n  "version": "1.0.0",\n  "main": "index.ts",\n  "license": "MIT",\n  "dependencies": {\n    "axios": "^0.26.0",\n    "react-query": "^3.34.16",\n    "styled-components": "^5.3.3"\n  },\n  "devDependencies": {\n    "@types/styled-components": "^5.1.24"\n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

和网络包(完美运行)

\n
{\n  "name": "@sharecode/web",\n  "version": "0.1.0",\n  "private": true,\n  "dependencies": {\n    "@testing-library/jest-dom": "^5.16.2",\n    "@testing-library/react": "^12.1.3",\n    "@testing-library/user-event": "^13.5.0",\n    "@types/jest": "^27.4.1",\n    "@types/node": "^16.11.26",\n    "@types/react": "^17.0.39",\n    "@types/react-dom": "^17.0.13",\n    "react": "17.0.2",\n    "react-dom": "^17.0.2",\n    "react-scripts": "^5.0.0",\n    "typescript": "^4.6.2",\n    "web-vitals": "^2.1.4"\n  },\n  "scripts": {\n    "start": "react-app-rewired start",\n    "build": "react-app-rewired build",\n    "test": "react-app-rewired test",\n    "eject": "react-app-rewired eject"\n  },\n  "eslintConfig": {\n    "extends": [\n      "react-app",\n      "react-app/jest"\n    ]\n  },\n  "browserslist": {\n    "production": [\n      ">0.2%",\n      "not dead",\n      "not op_mini all"\n    ],\n    "development": [\n      "last 1 chrome version",\n      "last 1 firefox version",\n      "last 1 safari version"\n    ]\n  },\n  "devDependencies": {\n    "eslint-config-react-app": "^7.0.0",\n    "react-app-rewired": "^2.2.1"\n  }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

该错误似乎非常简单,但我看不到发生了什么

\n
 ERROR  Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.\n\nThis error is located at:\n    in QueryClientProvider (at App.tsx:31)\n    in App (at renderApplication.js:50)\n    in RCTView (at View.js:32)\n    in View (at AppContainer.js:92)\n    in RCTView (at View.js:32)\n    in View (at AppContainer.js:119)\n    in AppContainer (at renderApplication.js:43)\n    in NuoDoor(RootComponent) (at renderApplication.js:60)\n\xe2\x9c\xa8  Done in 318.43s.\n\n
Run Code Online (Sandbox Code Playgroud)\n

另外,这是“yarn Why React”的结果

\n
javiermanzano@Javiers-MBP app % yarn why react\nyarn why v1.22.17\n[1/4]   Why do we have the module "react"...?\n[2/4]   Initialising dependency graph...\n[3/4]   Finding dependency...\n[4/4]   Calculating file sizes...\n=> Found "@sharecode/app#react@17.0.2"\ninfo Reasons this module exists\n   - "_project_#@sharecode#app" depends on it\n   - in the nohoist list ["/_project_/@sharecode/app/react-native","/_project_/@sharecode/app/react-native/**","/_project_/@sharecode/app/react","/_project_/@sharecode/app/react/**","/_project_/@sharecode/app/react-query","/_project_/@sharecode/app/react-query/**"]\ninfo Disk size without dependencies: "356KB"\ninfo Disk size with unique dependencies: "404KB"\ninfo Disk size with transitive dependencies: "432KB"\ninfo Number of shared dependencies: 3\n=> Found "react@17.0.2"\ninfo Reasons this module exists\n   - "_project_#@sharecode#web" depends on it\n   - Hoisted from "_project_#@sharecode#web#react"\ninfo Disk size without dependencies: "356KB"\ninfo Disk size with unique dependencies: "404KB"\ninfo Disk size with transitive dependencies: "432KB"\ninfo Number of shared dependencies: 3\n\xe2\x9c\xa8  Done in 1.17s.\n\n
Run Code Online (Sandbox Code Playgroud)\n

我希望我解释了这个问题!如有任何帮助,我们将不胜感激:)

\n

谢谢你!

\n

Lui*_*rdi 2

我不认为你的问题与 React 和渲染器版本不匹配有关,所以我们以 2 个选项结束。

\n

选项1:

\n
\n

3. You might have more than one copy of React in the same app

\n
\n

我将开始介绍第三个,因为这是最有可能的,在这种情况下,您的程序正在检测两个反应。

\n

在您的文件中,yarn why react您有一个react来自"_project_#@sharecode#app"和 的"_project_#@sharecode#web" Hoisted from "_project_#@sharecode#web#react"信息,请记住此提升信息,因为它对于解决您的问题很重要。

\n

看看你的,package.json你确实react都安装了。看着你workspaces nohoist"@sharecode/app"不要吊装react包裹,但正如我之前所说,它正在吊装!

\n

那么问题出在哪里呢?

\n

好吧,据我了解并在 nohoist 文档中进行了说明,您需要将nohoist配置放在“monorepo”package.json中(在您的情况下为)。@sharecode/common

\n

它看起来像这样:

\n
{\n  "name": "@sharecode/common",\n  ...,\n  "devDependencies": {\n     ...\n  },\n  "workspaces": {\n     "packages": ["packages/*"],\n     "nohoist": [\n       ...,\n       "**/react",\n       "**/react/**",\n       ...\n    ]\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后,package.json当您运行时按预期工作,yarn why react您应该得到如下结果:

\n
...\n=> Found "@sharecode/app#react@17.0.2"\ninfo Reasons this module exists\n   - "_project_#@sharecode#app" depends on it\n   - in the nohoist list ["/_project_/**/react-native","/_project_/**/react-native/**","/_project_/**/react","/_project_/**/react/**","/_project_/**/react-query","/_project_/**/react-query/**"]\n...\n
Run Code Online (Sandbox Code Playgroud)\n

也许found也有"_project_#@sharecode#web",还有其他nohoist可能。我自己没有检查过,但是通过上面所说的更正,您应该一切正常。您可以检查以获取有关其工作原理的进一步说明。但我很确定问题是nohoist不在“root monorepo”中。

\n

PS:我尝试查找使用原因是什么"packages": ["packages/*"],,但没有找到。但我推断这就是说你正在提升所有不在 nohoist 中的东西。

\n

选项2:

\n
\n

2. You might be breaking the Rules of Hooks

\n
\n

好吧,如果您无法使用第一个选项解决您的问题,那么您的问题与钩子有关。

\n

我不知道这是否是您的问题,但您正在调用 aboolconst可能试图在某个地方更改它。你不能重构以使用 a 吗useState(false)

\n

还要检查您是否在某些子项中调用了循环、条件或嵌套函数内的某些钩子,如果我没有错过理解的话,可能是 QueryClientProvider。

\n

搜索Hooks 规则我发现了这个:

\n
\n

不要\xe2\x80\x99t 在循环、条件或嵌套函数内调用 Hook。相反,在任何早期返回之前,始终在 React 函数的顶层使用 Hooks。通过遵循此规则,您可以确保每次渲染组件时都以相同的顺序调用 Hook。这\xe2\x80\x99s 允许 React 在多个 useState 和 useEffect 调用之间正确保留 Hooks 的状态。(如果您\xe2\x80\x99好奇,我们\xe2\x80\x99将在下面深入解释这一点。)

\n
\n