后退按钮后反应路由器“历史”和“位置”不匹配
Posted
技术标签:
【中文标题】后退按钮后反应路由器“历史”和“位置”不匹配【英文标题】:React Router `history` and `location` mismatched after back button 【发布时间】:2020-04-22 11:07:56 【问题描述】:在我的 React 应用程序中,从主页导航到子页面然后点击后退按钮后,React <Router>
显示其内部状态与从 history
传递的道具不匹配的位置以及不正确的 <Route>
为地址栏中当前显示的 URL 显示
<Route>
的内容确实发生了变化;数据由位置更改 Redux 操作更新。显示的<Route>
显示的是新数据,但是是错误的<Route>
。
应用的基本结构是:
<Root> (custom)
<Provider> (react-redux)
<ConnectedRouter> (connected-react-router)
<App> (custom)
<Switch> (react-router-dom)
<Route path="/" exact /> (react-router-dom)
<Route path="/quality:q" /> (react-router-dom)
最初我们导航到根目录,<Route path="/>
正确显示。我们单击一个链接,该链接正确地将我们带到<Route path="/quality/:q" />
。从那里我们返回浏览器,URL 更改为 /
,但 <Route path="/quality:q" />
仍然显示,但它不应该再显示了。
Redux devtools 显示了这个渲染树,我在其中包含了一些由我们明确使用的组件添加的关键组件。
<Root> (custom)
<Provider> (react-redux)
<ConnectedRouter> (connected-react-router)
<Router> (injected)
<Context.Provider> (injected)
<App> (custom)
<Switch> (react-router-dom)
<Route path="/" exact /> (react-router-dom)
<Route path="/quality:q" /> (react-router-dom)
当处于这种错误状态时,直到<ConnectedRouter>
的所有内容都是正确的。 <ConnectedRouter>
有一个单独的 prop,它是 history
,它具有正确的位置,即根。
紧随其后的<Router>
不匹配。它有一个 history
属性,没问题,但它有一个陈旧的 location
状态,显示旧网址。
当错误的位置数据被上下文传递给<Route>
s 时,他们会从location
属性中获得检查路径,该属性匹配<Router>
的陈旧状态。结果,渲染了错误的<Route>
。
我无法弄清楚我做了什么导致这种不匹配。这都是简单的路线,并使用<Link>
组件作为从主页到子页面和返回的所有链接。
以前有没有人见过这个和/或可以指出如何解决这个问题的方向?
【问题讨论】:
我遇到了类似的问题,history.location 正确但 location 不正确,您能找出原因吗? 【参考方案1】:我认为您的路由结构需要重构,因为您尝试匹配(可能是嵌套的)URL。
如果您希望/quality/:id
低于/
,则Route
需要是component
的子代。
例如,Route
将是:
<Route path="/" component=Home />
然后在Home
组件中,您将拥有使用match.url
(route props) 作为字符串匹配器的子Route
s:
const Home = ( match: url ) => (
<>
<div>Home<Home>
<Switch>
<Route path=`$urlquality/:q` component=Quality />
<Route path=`$urlsome/other/route` component=Example />
</Switch>
</>
);
但是,如果您想要相反的情况,即/
独立于/quality/:p
,那么您需要使用exact
:
<Switch>
<Route exact path="/" component=Home />
<Route exact path="/quality/:p" component=Quality />
<Route exact path="/some/other/route" component=Example />
<Switch>
工作示例
在本例中,/home
、/about
和 /dashboard
是相互独立的路由;但是,/dashboard
是这些子路由的父级:/dashboard/settings
和 /dashboard
(顺序很重要!)和 /dashboard
呈现一个 Dashboard
组件,它也恰好是 /dashboard/profile
子路由的父级! Order 和 exact
对于每个嵌套路由的渲染方式很重要。我还在pages/Profile
中包含了一个goBack
示例,以证明connected-react-router
的历史记录与react-router-dom
路由历史记录路由保持一致。
demo
source
如果您遵循上述约定,那么唯一的另一个问题是react-hot-loader
正在阻止状态更改。我个人不使用 RHL,因为我发现它相当有问题,但对每个人来说都是如此。也就是说,我在过去的 3 或 4 个项目中使用了connected-react-router
,并且我从来没有遇到过 props/state 不匹配的情况(除了一些共享的 redux 数据是陈旧的并且需要在加载另一个组件之前重置)正在重用相同的数据结构)。
【讨论】:
感谢您的回复。在简化发布消息时,我在根路由上省略了exact
关键字,但它在原始代码中。我更新了问题以澄清。
如果您可以创建可重现的代码和框演示(不需要花哨),那么它会更容易提供帮助。否则就是猜谜游戏。
同意,如果我可以重新创建,我可能会找到它。我正在逐行还原并重新应用自上次已知工作版本以来的更改,以查看导致此问题的原因。
要考虑的另一件事是,如果您使用的是服务工作者,那么它可能会缓存您的请求。
@SamuelNeff - 你最终解决了这个问题吗?如果是这样,解决方法是什么?【参考方案2】:
如果您使用 react-router 5+,您可以将位置从上层范围传递到 Switch。我从历史背景中传递过来。在我的情况下它解决了同样的问题
【讨论】:
【参考方案3】:我遇到了类似的问题。事实证明,我的树上有一个PureComponent
导致了它。使用withRouter
并将location
传递给PureComponent
解决了这个问题。
import withRouter from "react-router-dom";
const App = withRouter(( location, children ) => (
<IntlProvider location=location>
children
</IntlProvider>
));
ReactDOM.render(
<Root>
<Provider>
<ConnectedRouter>
<App>
<Switch>
<Route path="/" exact />
<Route path="/quality:q" />
</Switch>
</App>
</ConnectedRouter>
</Provider>
</Root>
【讨论】:
以上是关于后退按钮后反应路由器“历史”和“位置”不匹配的主要内容,如果未能解决你的问题,请参考以下文章