【问题标题】:React and antd: Router doesn't re-render componentsReact 和 antd:路由器不会重新渲染组件
【发布时间】: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 时,它工作正常,但我不能使用我自己的历史记录。

【问题讨论】:

    标签: reactjs react-router antd


    【解决方案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,我认为您必须自己管理同步(例如&lt;Link onClick={() =&gt; history.push(href)}&gt;) 或收听历史记录以进行更改检测。请参阅Detect Route Change with react-router

    【讨论】:

    • 这是否解释了我收到警告的原因:You cannot change the history of Router
    • 这是真的,但还有更简单的方法,例如useLocation钩子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-25
    • 2023-03-13
    • 2021-09-26
    • 2020-07-24
    • 2019-01-13
    相关资源
    最近更新 更多