如何在外部 npm 包中使用 React 的 Link 组件而不会出现错误:不变的“你不应该在路由器外部使用链接”
Posted
技术标签:
【中文标题】如何在外部 npm 包中使用 React 的 Link 组件而不会出现错误:不变的“你不应该在路由器外部使用链接”【英文标题】:How do I use React's Link component in an external npm package without error: invariant "you should not use link outside router" 【发布时间】:2020-03-15 21:09:02 【问题描述】:我创建了一个呈现图标菜单的 NPM 包(将在各种项目中使用)。允许用户向该图标菜单发送“路线”道具。因此,每个图标都可以是指向不同页面的链接。
但是,当我导入我的包时,我不断收到以下错误:
错误:不变量失败:您不应在
<Router>
之外使用<Link>
即使我在项目的路由器中导入和渲染图标菜单。或者,在这种情况下,是 BrowserRouter。
因为这是一个巨大的项目,所以我很快将这个过程分为两部分进行了重新创建。 请记住,该包是一个 NPM 包。如果它是我项目中的一个组件,那将不是问题。但是,我在不同的、相同的项目中需要这个包。
第 1 部分:NPM 包
IconMenu.js
import React from 'react';
import Icon from '@IDB/react-iconlibrary';
import Link from 'react-router-dom';
const IconMenu = ( items ) =>
return (
<div className='icon_menu'>
items.map((item, index) => (
<Link to=item.route>
<Icon className='icon_box_icon' key=index name=item.icon title=item.name />
</Link>
))
</div>
)
export default IconMenu
第 2 部分:项目
Project.js
import IconMenu from '@IDB/ui-elements';
import React, Component from 'react';
import BrowserRouter, Route from 'react-router-dom';
export default class Project extends Component
render ()
return (
<BrowserRouter>
<div id='page'>
<Route path='/' render=(props) => (
<IconMenu
items=[
icon: 'Edit',
name: 'Edit page',
route: '/edit'
,
icon: 'View',
name: 'View page',
route: '/save'
]
/>
)
/>
</div>
</BrowserRouter>
)
【问题讨论】:
尝试使用withRouter
像这样的IconMenu 组件 - export default withRouter(IconMenu);
我刚试了下,还是报错。虽然它现在说: > 错误:不变失败:您不应该在 更新
这只是在避免这个问题。实际解决方案见Sunknudsen's answer
开始原始答案
所以,这不是最好的解决方案,并且确实避免了这个问题,但这就是我解决它的方法。
第 1 部分:NPM 包
IconMenu.js
import React from 'react';
import Icon from '@IDB/react-iconlibrary';
const IconMenu = ( items ) =>
return (
<div className='icon_menu'>
items.map((item, index) => (
item.render(<Icon className='icon_box_icon' key=index name=item.icon title=item.name />)
))
</div>
)
export default IconMenu
第 2 部分:项目
Project.js
import IconMenu from '@IDB/ui-elements';
import React, Component from 'react';
import BrowserRouter, Route, Link from 'react-router-dom';
export default class Project extends Component
render ()
return (
<BrowserRouter>
<div id='page'>
<Route path='/' render=(props) => (
<IconMenu
items=[
icon: 'Edit',
name: 'Edit page',
render: (item) => <Link to='/test'>item</Link>
,
icon: 'View',
name: 'View page',
render: (item) => <Link to='/test'>item</Link>
]
/>
)
/>
</div>
</BrowserRouter>
)
【讨论】:
感谢分享塞德里克。您最终是否设法将 Link 包含在您的包中? @sunknudsen 不是;但我也进入了另一个项目,我们使用 Next.js 的静态页面进行路由。因此,上述问题将不再相关。但是,我不认为我的解决方案是“最终的”。如果其他人有更好的解决方案允许在外部包中使用 Link,那就太棒了。 嘿 Cédric,经过数小时的调试,我相信我找到了问题所在。请参阅下面的答案。【参考方案2】:我有一个similar issue 并且能够使用以下方法解决它。
但首先,我们为什么会遇到这种极端情况?
当react-router-dom
的两个实例存在且conflict 彼此存在时,将引发此错误。
在我的用例中,这发生在我使用 npm link
“安装”我正在开发的一个 npm 包以抽象 Link
时。
我相信这个问题中描述的用例,也许 react-router-dom
是作为依赖项安装的,而它本应作为 peer dependency 安装(以减轻冲突)。
这是我package.json
的摘录。
"name": "react-hashlink",
"peerDependencies":
"react": "^17.0.0",
"react-dom": "^17.0.0",
"react-router-dom": "^5.0.0"
,
"dependencies": ,
"devDependencies":
"@types/react": "^17.0.0",
"@types/react-router-dom": "^5.1.7",
"npm-check-updates": "^10.2.5",
"typescript": "^4.1.3"
受 React docs 启发的解决方案
一种可能的解决方法是从
mylib
运行npm link ../myapp/node_modules/react
。这应该使库使用应用程序的 React 副本。
我创建了两个帮助脚本来链接和取消链接宿主项目的对等依赖项。
.env
PEER_DEPS_NODE_MODULES_PATH=/Users/sunknudsen/Code/sunknudsen/sunknudsen-website/node_modules
link-peer-deps.sh
#!/bin/sh
if [ -f .env ]
then
export $(cat .env | sed 's/#.*//g' | xargs)
fi
npm link \
$PEER_DEPS_NODE_MODULES_PATH/react \
$PEER_DEPS_NODE_MODULES_PATH/react-dom \
$PEER_DEPS_NODE_MODULES_PATH/react-router-dom
unlink-peer-deps.sh
#!/bin/sh
npm unlink react react-dom react-router-dom
希望这对其他人有所帮助!
【讨论】:
伟大的发现@sunknudsen!感谢分享。我确实希望这个问题将来可以帮助其他人。以上是关于如何在外部 npm 包中使用 React 的 Link 组件而不会出现错误:不变的“你不应该在路由器外部使用链接”的主要内容,如果未能解决你的问题,请参考以下文章