React Router Dom v6.4 不允许使用 createBrowserRouter 或 createMemoryRouter 进行 history.listen(先前的建议已弃用)



react router dom v.6.4.2不允许使用下面代码示例中提到的history.listen。这是针对带有模块联合的mfe。

在使用history.listen的代码示例中,如果在远程(加载为mfe)中单击链接,则将更新内存历史(现在是内存路由器)的当前路径。然后,它将调用onNavigate,告诉正在使用浏览器历史记录的主机容器(现在是浏览器路由器)当前路径已更改。

以前的建议是使用UNSAFE_NavigationContext、useHistory、unsable_HistoryRouter、从"history"导入{…}等。显然,这些以前的方法是从v5到v6.3的临时迁移辅助工具,而v6.4+现在被弃用,取而代之的是6.4中的新数据api。参见此处

我们不打算支持自定义历史向前发展。本API作为移民援助。我们建议删除自定义历史记录从您的应用程序。

此外,来自RRD:的维护人员

我们建议您更新应用程序,使用6.4版本的新路由器之一。

在此处以及在remix RRD的打开和关闭问题中搜索后,我无法找到基于以上内容的可行解决方案,使用此处引用的createBrowserRouter或createMemoryRouter将history.listen、.push或.location替换为新的数据api(路由器)

react router dom页面上有许多与此用例相关的未决问题。

来自远程的原始营销/src/bootstrap.tsx

import React from 'react'
import { createRoot } from 'react-dom/client'
import { createMemoryHistory, createBrowserHistory } from 'history' <= Not Supported
import App from './App'
let root: { render: (arg0: JSX.Element) => void } | null = null
// Mount function to start up the app
const mount = (el: any, { onNavigate, defaultHistory, initialPath }: any) => {
if (!el) {
root = null
return
}
// If defaultHistory in development and isolation use BrowserHistory
const history =
defaultHistory ||
// Otherwise use MemoryHistory and initial path from container
createMemoryHistory({
initialEntries: [initialPath],
})
if (onNavigate) {
history.listen(onNavigate)                  <= Not Supported
}
root = root ? root : createRoot(el)
root.render(<App history={history} />)
return {
onParentNavigate({ pathname: nextPathname }: any) {
const { pathname } = history.location      <= Not Supported
if (pathname !== nextPathname) {
history.push(nextPathname)               <= Not Supported
}
},
}
}
// If we are in development and in isolation,
// call mount immediately
if (process.env.NODE_ENV === 'development') {
const devRoot = document.querySelector('#_marketing-dev-root')
if (devRoot) {
mount(devRoot, { defaultHistory: createBrowserHistory() })
}
}
// We are running through container
// and we should export the mount function
export { mount }

从远程(进行中)替换市场营销/src/bootstrap.tsx

import React from 'react'
import { createRoot } from 'react-dom/client'
import {
createBrowserRouter,
createMemoryRouter,
} from 'react-router-dom'
import App from './App'
import ErrorPage from './pages/ErrorPage'
import Landing from './components/Landing'
import Pricing from './components/Pricing'
let root: { render: (arg0: JSX.Element) => void } | null = null
const routes = [
{
path: '/',
errorElement: <ErrorPage />,
children: [
{
index: true,
element: <Landing />,
errorElement: <ErrorPage />,
},
{
path: 'pricing',
element: <Pricing />,
errorElement: <ErrorPage />,
},
],
},
]
// Mount function to start up the app
const mount = (
el: Element,
{
onNavigate,
defaultRouter,
}: {
onNavigate: (() => void) | null
defaultRouter: any
},
): unknown => {
if (!el) {
root = null
return
}
// if in development and isolation, use browser router. If not, use memory router
const router = defaultRouter || createMemoryRouter(routes)
if (onNavigate) {
router.listen(onNavigate) // There is no history.listen anymore.  router.listen is not a function
}
root = root ? root : createRoot(el)

root.render(<App router={router} />)
}
// If we are in development and in isolation,
// call mount immediately
if (process.env.NODE_ENV === 'development') {
const devRoot = document.querySelector('#_marketing-dev-root')
if (devRoot) {
mount(devRoot, { defaultRouter: createBrowserRouter(routes) })
console.log('defaultRouter')
}
}
// We are running through container
// and we should export the mount function
export { mount }

来自远程的原始营销/src/App.tsx

import './MuiClassNameSetup'
import React from 'react'
import { Switch, Route, Router } from 'react-router-dom'
import Landing from './components/Landing'
import Pricing from './components/Pricing'
export default function _({ history }: any) {
return (
<div>
<Router history={history}>
<Switch>
<Route exact path="/pricing" component={Pricing} />
<Route path="/" component={Landing} />
</Switch>
</Router>
</div>
)
}

来自远程(正在进行中)的替代营销/src/App.tsx

import './MuiClassNameSetup'
import React from 'react'
import {
RouterProvider,
} from 'react-router-dom'
export default function App({ router }: any) {
return <RouterProvider router={router} />
}

来自主机的原始容器/src/components/MarkingApp.tsx

import { mount } from 'marketing/MarketingApp'
import React, { useRef, useEffect } from 'react'
import { useHistory } from 'react-router-dom'   <= Not Supported
export default function _() {
const ref = useRef(null)
const history = useHistory()                  <= Not Supported
useEffect(() => {
const { onParentNavigate } = mount(ref.current, {
initialPath: history.location.pathname,
onNavigate: ({ pathname: nextPathname }: any) => {
const { pathname } = history.location   <= Not Supported
if (pathname !== nextPathname) {
history.push(nextPathname)            <= Not Supported
}
},
})
history.listen(onParentNavigate)            <= Not Supported
}, [history])
return <div ref={ref} />
}

从主机(正在进行中)更换容器/src/components/MarkingApp.tsx

import { mount } from 'marketing/MarketingApp'
import React, { useRef, useEffect } from 'react'
export default function _() {
const ref = useRef(null)
useEffect(() => {
mount(ref.current, {
onNavigate: () => {
console.log('The container noticed navigation in Marketing')
},
})
})
return <div ref={ref} />
}

正在寻找一个替代history.listen、history.location和history.push的解决方案,以使用新的v6.4数据api?

RRD的一位维护人员刚刚发布了一个新的实现细节,以取代适用于v6.4+的history.listen。请参阅下面的router.subscribe()

let router = createBrowserRouter(...);
// If you need to navigate externally, instead of history.push you can do:
router.navigate('/path');
// And instead of history.replace you can do:
router.navigate('/path', { replace: true });
// And instead of history.listen you can:
router.subscribe((state) => console.log('new state', state));

不幸的是,新的实现也是不稳定的,并且被认为是测试版的实现。

现在,对于坏消息。就像不稳定的历史路由器一样,我们考虑这种类型的外部导航和订阅不稳定,这就是为什么我们没有记录这一点,也就是为什么我们标记了所有路由器API均为@internal PRIVATE-请勿在中使用JSDoc/Typescript。这并不是说他们将永远不稳定,但由于这不是路由器的正常预期用途,我们仍然确保这种类型的外部导航不会引入问题(我们很有信心在react 18中引入useSyncExternalStore!)

如果您的应用程序需要这种类型的导航,并且您需要使用RouterProvider时替换不稳定_HistoryRouter我们鼓励您使用router.navigation和router.subscribe方法并帮助我们测试该方法!请随时打开新GH如果您使用该方法遇到任何问题,我们将使用它们帮助我们呼吁将其推向未来的稳定发布。

最新更新