gpt4 book ai didi

reactjs - React Router Dom v6.4 不允许使用 createBrowserRouter 或 createMemoryRouter 进行 history.listen(不推荐使用之前的建议)

转载 作者:行者123 更新时间:2023-12-05 05:32:17 36 4
gpt4 key购买 nike

react-router-dom v. 6.4.2 不允许 history.listen,如下面的代码示例所引用。这是针对具有模块联合的 mfe。

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

之前的建议是使用 UNSAFE_NavigationContext、useHistory、unstable_HistoryRouter、import {...} from 'history' 等。显然,这些之前的方法是从 v5 到 v6.3 的临时迁移辅助工具,现在是 v6.4+已弃用以支持 6.4 中的新数据 API。参见 here

we do not intend to support custom histories moving forward. This APIis here as a migration aid. We recommend removing custom historiesfrom your app.

此外,from the maintainers of RRD :

We recommend updating your app to use one of the new routers from 6.4.

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

react-router-dom 页面上有许多与 this use case 相关的未解决问题.

来自远程的原始 marketing/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 }

从远程替换 marketing/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 }

来自远程的原始 marketing/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>
)
}

从远程替换 marketing/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/MarketingApp.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/MarketingApp.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 的一位维护者刚刚发布了一个 new implementation detail to replace history.listen适用于 v6.4+。请参阅下面的 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));

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

Now, for the bad news 😕 . Just like unstable_HistoryRouter we alsoconsider this type of external navigation and subscribing to beunstable, which is why we haven't documented this and why we've markedall the router APIs as @internal PRIVATE - DO NOT USE inJSDoc/Typescript. This isn't to say that they'll forever be unstable,but since it's not the normally expected usage of the router, we'restill making sure that this type of external-navigation doesn'tintroduce problems (and we're fairly confident it doesn't with theintroduction of useSyncExternalStore in react 18!)

If this type of navigation is necessary for your app and you need areplacement for unstable_HistoryRouter when using RouterProvider thenwe encourage you use the router.navigate and router.subscribe methodsand help us beta test the approach! Please feel free to open new GHissues if you run into any using that approach and we'll use them tohelp us make the call on moving that towards future stable release.

关于reactjs - React Router Dom v6.4 不允许使用 createBrowserRouter 或 createMemoryRouter 进行 history.listen(不推荐使用之前的建议),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74165853/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com