history.push() 后组件未呈现

Component is not getting rendered after history.push()

单击按钮后,我通过 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 中传递 history,我认为这与使用 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 

但没有得到任何运气。谁能解释为什么会这样?
P.S 我看了答案 但他们没有帮助

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

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

routes(在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,因为像[=这样的组件30=] 不在 <Route "/example" component={Header}/> 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 这样的组件知道路由,并且 history 对象已经通过 <Route path="/" component={Home} /> HOC,所以不需要 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(在自己的文件中定义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(仍然知道路由并且已经通过 <Route path="/" component={Home} /> 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>
);

几点:

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) 将 history 导入主文件并将其传递到 Router 组件中。

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>
        )
    }
}

希望对您有所帮助..

:)

使用 import { Router } 而不是 import { BrowserRouter as Router } 。 因为 BrowserRouter 忽略了 history prop.

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

兼容

这个组合没有对我有用:

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

这个组合做了:

历史:4.10.1 和 react-router-dom 5.2.0

检查 react 版本, react-router, react-router-dom 和 history package 版本也是无能为力 – 我的配置 package.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"

检查这个 link :- 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

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

  const { pathname } = useLocation();

每次路径名更改时组件都会重新呈现。

将历史包降级为历史:4.10.1 with react-router-dom 5.2.0 对我有用

使用这个:

import { useHistory, useRouteMatch } from 'react-router-dom';

let history = useHistory();
let match = useRouteMatch();