React 和 antd:路由器不会重新渲染组件
Posted
技术标签:
【中文标题】React 和 antd:路由器不会重新渲染组件【英文标题】:React and antd: Router doesn't re-render components 【发布时间】:2021-02-25 10:54:43 【问题描述】:我有一个带有登录和搜索页面的简单网页。我在顶部还有一个导航栏,可以在两者之间切换。基本的App.js
如下所示:
const history = createBrowserHistory();
function App()
return (
<Router history=history>
<CustomLayout>
<Switch>
<BaseRouter/>
</Switch>
</CustomLayout>
</Router>
);
export default App;
现在,BaseRouter
和 CustomLayout
只是
const BaseRouter = () => (
<div>
<Route exact path="/list" component=ItemsList/>
<Route path="/login" component=LoginForm/>
</div>
);
export default BaseRouter;
和
const CustomLayout = (children) =>
return(
<>
<Navbar/>
children
</>
);
export default CustomLayout;
现在,导航栏看起来像这样
import React from "react";
import Menu from 'antd';
import Link from "react-router-dom";
const Navbar = () =>
return (
<div>
<Menu mode="horizontal" theme="dark">
<Menu.Item key="list">
<Link to="/list">List</Link>
</Menu.Item>
<Menu.Item key="login">
<Link to="/login">Sign in</Link>
</Menu.Item>
</Menu>
</div>
);
export default Navbar
让我们保持组件简单:
const Login = () =>
return (
<div>
login
</div>
);
export default Login
const List = () =>
return (
<div>
list
</div>
);
export default List
现在的问题是,当我单击导航栏中的链接时,即使路线发生变化,React 也不会重新渲染组件。我已经在 SO 上看到了数百个答案,但我仍然无法弄清楚。注意
避免刷新或重新加载页面对我来说很重要。编辑
奇怪的是,当我将 Router
更改为 BrowserRotuer
时,它工作正常,但我不能使用我自己的历史记录。
【问题讨论】:
【参考方案1】:为什么不使用 react-router-dom
包中的 BrowserRouter
。
App.js
:- 使用来自react-router-dom
的BrowserRouter
import BrowserRouter as Router, Switch from 'react-router-dom'
function App()
return (
<Router>
<CustomLayout>
<Switch>
<BaseRouter/>
</Switch>
</CustomLayout>
</Router>
);
export default App;
BaseRouter.js
:- 从react-router-dom
导入Route
import Route from 'react-router-dom'
const BaseRouter = () => (
<div>
<Route exact path="/list" component=ItemsList/>
<Route path="/login" component=LoginForm/>
</div>
);
export default BaseRouter;
Navbar.js
:-
import React from "react";
import Menu from 'antd';
import Link from "react-router-dom";
const Navbar = () =>
return (
<div>
<Menu mode="horizontal" theme="dark">
<Menu.Item key="list">
<Link to="/list">List</Link>
</Menu.Item>
<Menu.Item key="login">
<Link to="/login">Sign in</Link>
</Menu.Item>
</Menu>
</div>
);
export default Navbar
那么如果你想使用history
:-
import useHistory from 'react-router-dom'
const testFunctionComponent = () =>
const history = useHistory()
const handleClick = (urlPath) =>
// you can do
history.push(urlPath) // to go anywhere
return (
<>
<button onClick=() => handleClick('/anypath')>Click Me!<button>
</>
)
【讨论】:
致任何阅读本文的人:这是最简单的方法。我还发现如果你使用BrowserRouter
,你可以在你喜欢的任何组件中调用props.history.push()
。
是的。对于作为BrowserRouter
下的子组件的所有组件都是如此。【参考方案2】:
从此更改您的BaseRouter
:
const BaseRouter = () => (
<div>
<Route exact path="/list" component=ItemsList/>
<Route path="/login" component=LoginForm/>
</div>
);
export default BaseRouter;
到这里:
const BaseRouter = () => (
<div>
<Route exact path="/list" component=ItemsList/>
<Route path="/login" component=LoginForm/>
</div>
);
export default BaseRouter;
【讨论】:
不,很抱歉,这并没有改变什么【参考方案3】:我相信您不能将 div 放在开关内。您没有将 Route 组件暴露给您的 switch 语句。
因此,您的 url 会发生变化,因为您的导航栏会使其发生变化,但您的开关不知道该怎么做。
尝试将您的基本路由器更改为:
const history = createBrowserHistory();
function App()
return (
<Router history=history>
<CustomLayout>
<BaseRouter/>
</CustomLayout>
</Router>
);
export default App;
const BaseRouter = () => (
<Switch>
<Route exact path="/list" component=ItemsList/>
<Route path="/login" component=LoginForm/>
</Switch>
);
export default BaseRouter;
【讨论】:
不,很抱歉,这并没有改变什么【参考方案4】:Router
是低级的,希望您管理事物。 BrowserRouter
已经与 html5 历史同步。如果您想要Router
,我认为您必须自己管理同步(例如<Link onClick=() => history.push(href)>)
或收听历史记录以进行更改检测。请参阅Detect Route Change with react-router
【讨论】:
这是否解释了我收到警告的原因:You cannot change the history of Router
这是真的,但还有更简单的方法,例如useLocation
钩子以上是关于React 和 antd:路由器不会重新渲染组件的主要内容,如果未能解决你的问题,请参考以下文章
使用 React Router 重新加载 Webpack HotModule 渲染与组件
如何在 react 中的新路由更改上使用 useEffect 重新渲染变量