【问题标题】:Component is not getting rendered after history.push()组件在 history.push() 之后没有被渲染
【发布时间】:2019-08-03 10:50:12
【问题描述】:

单击按钮后,我通过 history.push() 更改了 URL

import createHistory from 'history/createBrowserHistory'  
const history = createHistory()  
.  
. some code  
.  
history.push(`/share/${objectId}`)

并希望Route 中提到的用于该 URL 的组件能够呈现,但这并没有发生。不过,在刷新该组件时,它会按预期呈现。但我不明白为什么它不会在 URL 更改后立即呈现。我尝试将组件包装在withRouter 中。

import React, {Component} from 'react'  
import {BrowserRouter, Router, Route, Switch, withRouter} from 'react-router-dom'  
import createHistory from 'history/createBrowserHistory'  

import Home from './pages/home'  
import ViewFile from './pages/view-file'  

const history = createHistory()

class App extends Component {
    constructor(props) {
      super(props)
    }

      render() {
      return (
          <BrowserRouter>
              <Switch>
                  <Route exact path={'/'} component={Home}/>
                  <Route path={'/share/:id'} component={withRouter(ViewFile)}/>
              </Switch>
          </BrowserRouter>
      )
  }
}

export default App 

以及在Router 中传递历史,我认为这与使用BrowserRouter 相同。

import React, {Component} from 'react'  
import {BrowserRouter, Router, Route, Switch, withRouter} from 'react-router-dom'  
import createHistory from 'history/createBrowserHistory'  

import Home from './pages/home'  
import ViewFile from './pages/view-file'  

const history = createHistory()

class App extends Component {
    constructor(props) {
      super(props)
    }

      render() {
      return (
          <Router history={history}>
              <Switch>
                  <Route exact path={'/'} component={Home}/>
                  <Route path={'/share/:id'} component={ViewFile}/>
              </Switch>
          </Router>
      )
  }
}

export default App 

但没有得到任何运气。谁能解释为什么会发生这种情况?
PS 我浏览了here 的答案,但他们没有帮助

【问题讨论】:

标签: reactjs react-router browser-history history.js


【解决方案1】:

每次调用createHistory() 时都会创建新的历史记录。如果您使用react-router-dom,您可以简单地使用withRouter HOC,它将通过prophistory 对象提供给组件。然后您将使用history.push('/'),或者如果它位于class componentthis.props.history.push('/') 等中。

工作示例https://codesandbox.io/s/p694ln9j0

路由(在routes 中定义history

import React from "react";
import { Router, Route, Switch } from "react-router-dom";
import { createBrowserHistory } from "history";
import Header from "../components/Header";
import Home from "../components/Home";
import About from "../components/About";
import Contact from "../components/Contact";
import ScrollIntoView from "../components/ScrollIntoView";

const history = createBrowserHistory();

export default () => (
  <Router history={history}>
    <div>
      <ScrollIntoView>
        <Header />
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/contact" component={Contact} />
        </Switch>
        <Header />
      </ScrollIntoView>
    </div>
  </Router>
);

components/Header.js(我们想访问history,但是,有时我们必须使用withRouter,因为像Header 这样的组件不驻留在&lt;Route "/example" component={Header}/&gt; HOC 中,所以它不知道我们的路由)

import React from "react";
import { withRouter } from "react-router-dom";

const Header = ({ history }) => (
  <header>
    <nav style={{ textAlign: "center" }}>
      <ul style={{ listStyleType: "none" }}>
        <li style={{ display: "inline", marginRight: 20 }}>
          <button onClick={() => history.push("/")}>Home</button>
        </li>
        <li style={{ display: "inline", marginRight: 20 }}>
          <button onClick={() => history.push("/about")}>About</button>
        </li>
        <li style={{ display: "inline", marginRight: 20 }}>
          <button onClick={() => history.push("/contact")}>Contact</button>
        </li>
      </ul>
    </nav>
  </header>
);

export default withRouter(Header);

components/Home.js(像Home 这样的组件知道路由并且已经通过&lt;Route path="/" component={Home} /&gt; HOC 传入了history 对象,所以withRouter 不是必填)

import React from "react";

const Home = ({ history }) => (
  <div className="container">
    <button
      className="uk-button uk-button-danger"
      onClick={() => history.push("/notfound")}
    >
      Not Found
    </button>
    <p>
      ...
    </p>
  </div>
);

export default Home;

但是,如果您不想使用withRouter,则与上面的概念相同,那么您可以简单地创建一个history 实例,该实例将在需要它的组件之间共享。您将import 这个history 实例并使用history.push('/'); 导航等等。

工作示例https://codesandbox.io/s/5ymj657k1k

历史(在自己的文件中定义history

import { createBrowserHistory } from "history";

const history = createBrowserHistory();

export default history;

路由(将history 导入routes

import React from "react";
import { Router, Route, Switch } from "react-router-dom";
import Header from "../components/Header";
import Home from "../components/Home";
import About from "../components/About";
import Contact from "../components/Contact";
import ScrollIntoView from "../components/ScrollIntoView";
import history from "../history";

export default () => (
  <Router history={history}>
    <div>
      <ScrollIntoView>
        <Header />
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/contact" component={Contact} />
        </Switch>
        <Header />
      </ScrollIntoView>
    </div>
  </Router>
);

components/Header.js(将history 导入Header

import React from "react";
import history from "../history";

const Header = () => (
  <header>
    <nav style={{ textAlign: "center" }}>
      <ul style={{ listStyleType: "none" }}>
        <li style={{ display: "inline", marginRight: 20 }}>
          <button onClick={() => history.push("/")}>Home</button>
        </li>
        <li style={{ display: "inline", marginRight: 20 }}>
          <button onClick={() => history.push("/about")}>About</button>
        </li>
        <li style={{ display: "inline", marginRight: 20 }}>
          <button onClick={() => history.push("/contact")}>Contact</button>
        </li>
      </ul>
    </nav>
  </header>
);

export default Header;

components/Home.js(仍然知道路由并且已经通过 &lt;Route path="/" component={Home} /&gt; HOC 传入了 history 对象,因此不需要导入 history,但是您如果你愿意,仍然可以导入它——只是不要在Home的函数参数中解构history

import React from "react";

const Home = ({ history }) => (
  <div className="container">
    <button
      className="uk-button uk-button-danger"
      onClick={() => history.push("/notfound")}
    >
      Not Found
    </button>
    <p>
      ...
    </p>
  </div>
);

export default Home;

但你可能会想,BrowserRouter 呢?好吧,BrowserRouter 有它自己的内部 history 对象。我们可以再次使用withRouter 访问其history。在这种情况下,我们甚至根本不需要createHistory()

工作示例https://codesandbox.io/s/ko8pkzvx0o

路线

import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Header from "../components/Header";
import Home from "../components/Home";
import About from "../components/About";
import Contact from "../components/Contact";
import Notfound from "../components/Notfound";
import ScrollIntoView from "../components/ScrollIntoView";

export default () => (
  <BrowserRouter>
    <div>
      <ScrollIntoView>
        <Header />
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/contact" component={Contact} />
          <Route component={Notfound} />
        </Switch>
        <Header />
      </ScrollIntoView>
    </div>
  </BrowserRouter>
);

【讨论】:

  • 非常感谢。昨天我在阅读 react router 的文档时浪费了几个小时,但不太了解。我认为您应该编写文档。
  • 它不起作用,我不知道为什么,我使用的是Router 而不是BrowserRouter,但我所有的组件都没有呈现,URL 发生了变化,但我总是得到404 后备路由组件。
  • @HassanAzzam 请使用您的示例代码创建MCVE,然后创建ask a new question
  • 与上面的代码完全相同,但它不起作用我什至尝试了history.listen,当我更改路线时它返回undefined
  • @HassanAzzam 看起来他们可能已经放弃了对在 v5 中使用您自己的历史对象的支持。写这篇文章时,v4.x.x 是最新的,因此它作为expected 工作。我鼓励你放弃这种方法,因为还有其他更好的选择(比如使用 BrowserRouteruseHistory 钩子或使用 withRouter 更高阶组件访问 history 如果你不使用钩子)
【解决方案2】:

几点:

1) 使用import { Router} from 'react-router-dom' 而不是import { BrowserRouter as Router} from 'react-router-dom'

2) 在不同的文件中创建变量history,即(可以更改)../src/services/history.js,内容应该是:

import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
export default history;

您必须通过npm install --save react-history 安装react-history 软件包

3) 将历史记录导入主文件并将其传递到路由器组件中。

import React from 'react';
import { Router, Route, Switch } from 'react-router-dom'
import history from './services/history'


class App extends React.Component {

    render() {
        return (
            <Router history={history}>
                <Switch>
                    <Route exact path='/' component={MainPage}></Route>
                    <Route exact path='/vendor' component={VendorPage}></Route>
                    <Route exact path='/client' component={ClientPage}></Route>
                </Switch>
            </Router>
        );
    }
}

export default App;

4) 现在您可以在组件中的任意位置使用history

import React from 'react'
import history from '../services/history';

export default class VendorPage extends React.Component {

    loginUser = () => {
        if (<SOME_CONDITION>)
            history.push('/client')
    }

    render() {
        return (
            <h1>Welcome to Vendor Page....</h1>
        )
    }
}

希望对你有帮助。

:)

【讨论】:

  • 我认为他可以使用react-router-domuseHistory() 钩子,这样他就不必安装另一个库了。
  • 不幸的是,这似乎不再起作用了
  • 这不适用于react-router-dom v6
【解决方案3】:

使用 import { Router } 代替 import { BrowserRouter as Router } 。 因为 BrowserRouter 忽略了 history 属性。

【讨论】:

  • 哇!就是这样!这么多小时试图找到这个! history.push() 的工作方式与 Router 一样。
  • 哇,比我想象的要容易得多。谢谢!
  • 将 BrowserRouter prod forceRefresh 设置为 true 也可以。 &lt;BrowserRouter forceRefresh={true}&gt;
【解决方案4】:

这可能对某人有所帮助。确保history 包版本与react-router-dom 兼容。

这种组合没有对我有用:

历史:5.0.0 与 react-router-dom:5.2.0

这个组合做到了

历史:4.10.1 与 react-router-dom 5.2.0

【讨论】:

  • 谢谢!我有同样的问题。
  • +1 这对我有用。我在 v 5.0.0 中的历史和在 5.2.0 中的 react-router-dom 完全相同!!!谢谢!拯救了我的一天;)
  • 非常感谢!花了一整天的时间寻找这个答案!!!
【解决方案5】:

检查 react 版本,react-router,react-router-dom 和历史包版本,这也是无能为力的 - 我的配置包.json

"history": "^4.10.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-router": "5.1.2",
"react-router-dom": "5.1.2"

检查此链接:- https://stackblitz.com/edit/react-34ohqv?embed=1&file=package.json https://stackblitz.com/edit/react-router-example-mahi-hzitgg?embed=1&file=index.js

【讨论】:

  • 花了 3 个小时来了解为什么历史记录不起作用,这就是原因。谢谢!
  • 完全正确!!!由于某种原因,历史版本 5 不起作用!当我降级到建议的版本时,效果很好。谢谢!
【解决方案6】:

对于使用钩子的人,使用 useLocation() 钩子而不是 useHistory() 有效。

  const { pathname } = useLocation();

每次路径名更改时组件都会重新渲染。

【讨论】:

    【解决方案7】:

    将历史包降级到历史记录:4.10.1 和 react-router-dom 5.2.0 对我有用

    【解决方案8】:

    使用这个:

    import { useHistory, useRouteMatch } from 'react-router-dom';
    
    let history = useHistory();
    let match = useRouteMatch();
    

    【讨论】:

      猜你喜欢
      • 2021-08-09
      • 2018-11-28
      • 1970-01-01
      • 2017-06-11
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 2018-05-19
      • 2020-01-22
      相关资源
      最近更新 更多