在Monorepo中使用react-responsive触发Invalid-hook-call错误求助
首先,Invalid-hook-call错误虽然提示在你的函数式组件里,但通常不是组件本身的问题,而是钩子的执行上下文不对。结合你的Monorepo+React Native Web+styled-components的场景,我整理了几个最可能的解决方向:
1. 优先排查Monorepo中重复的React实例
这是Monorepo里钩子错误的头号元凶:如果你的UI库和React Native应用各自安装了独立的React包,就会出现两个不同的React上下文,导致react-responsive内部的钩子无法识别当前组件的React环境。
解决步骤:
- 在UI库的
package.json中,把react、react-dom(如果用到)和react-native-web设为peerDependencies,而不是dependencies,确保UI库复用应用提供的React实例:"peerDependencies": { "react": "^17.0.0 || ^18.0.0", "react-dom": "^17.0.0 || ^18.0.0", "react-native-web": "^0.18.0" } - 在Monorepo根目录的
package.json中,用包管理器的统一版本锁定功能强制所有工作区使用相同的React版本:- 若用yarn:添加
resolutions字段"resolutions": { "react": "^18.2.0", "react-dom": "^18.2.0" } - 若用pnpm:添加
pnpm.overrides字段"pnpm": { "overrides": { "react": "^18.2.0", "react-dom": "^18.2.0" } }
- 若用yarn:添加
- 删除所有工作区的
node_modules和锁文件,重新安装依赖。
2. 替换react-responsive为更适配React Native Web的方案
react-responsive本质是为Web环境设计的,在React Native Web中可能存在环境适配问题(比如依赖浏览器的window对象,或钩子逻辑和RNW渲染流程冲突)。你可以改用styled-components原生的媒体查询能力,完全能实现相同需求,还能避免额外的钩子依赖:
修改你的Card组件,去掉react-responsive,直接在样式里写媒体查询:
import styled from 'styled-components/native'; import { theme } from '@components/theme'; interface CardProps { children: React.ReactNode; tag: string; } const Card = (props: CardProps) => { console.log("Card -> props", props) return ( <Container> <TagContainer> <Tag>{props.tag}</Tag> {/* 仅在桌面端显示的标签 */} <DesktopTag>'blablabla</DesktopTag> </TagContainer> <MainContent>{props.children}</MainContent> </Container> ); } // 新增桌面端专属标签样式 const DesktopTag = styled.Text` display: none; @media (min-width: 1000px) { display: block; /* 这里添加桌面端标签的样式 */ } `; // 其他样式保持不变 const Container = styled.View` display: flex; flexDirection: column; minWidth: ${theme.width.minCard}; maxWidth: ${theme.width.maxCard}; height: ${theme.height.card}; boxShadow: 0 0 10px ${theme.colors.primaryGrey}; border: 1px solid ${theme.colors.primaryYellow}; borderRadius: ${theme.borderRadius.rectangular}; marginBottom: ${theme.margins.medium}; `; const TagContainer = styled.View` display: flex; flexDirection: row-reverse; `;
这种方式完全利用styled-components的特性,和React Native Web的兼容性更好,也不会引入额外的钩子依赖。
3. 验证react-responsive的版本兼容性
如果一定要保留react-responsive,检查它的版本是否和你使用的React版本匹配:
- React 18需要react-responsive >= 9.0.0版本
- 如果你的React版本是17,确保react-responsive在8.x.x范围内
可以在UI库的package.json中明确指定兼容的版本,然后重新安装依赖。
4. 检查组件导出/导入的正确性
虽然可能性较低,但还是要确认UI库中的Card组件是正确导出为函数式组件,应用中是通过JSX语法调用(而不是当作普通函数执行)。比如UI库的导出是否是:
export default Card; // 或者 export const Card = (props: CardProps) => { ... }
应用中的导入是否对应正确的导出方式。
内容的提问来源于stack exchange,提问作者E.D

