history.push 更改 url,但未呈现组件

history.push changes url, but component is not rendered

为什么 Dashboard 组件在 history.push("/dashboard") 将 url 更改为 /dashboard 后没有渲染?

Gif showcasing the issue,如您所见,我必须手动单击刷新按钮才能触发重新渲染。


index.js

import ReactDOM from "react-dom";

import Router from "./Router";

const rootElement = document.getElementById("root");
ReactDOM.render(
    <Router />,
  rootElement
);

LoginForm.js

import React, {Component} from "react"

class LoginForm extends Component {

    handleSubmit = (event) => {
    event.preventDefault()
    this.props.history.push("/dashboard")
    }

    render() {
        return (
                <form name="signup_form" onSubmit={this.handleSubmit}>
                    <input type="submit" value="Sign Up"/>
                </form>
        )
    }

}

export default LoginForm

Router.js

import LoginForm from "./LoginForm";
import {BrowserRouter, Route, Switch } from "react-router-dom";
import React, {Component} from "react";
import { createBrowserHistory } from "history"

const browserHistory = createBrowserHistory()

class Router extends Component {

    render() {
        return (
                <BrowserRouter >
                    <LoginForm history={browserHistory} />
                    <Switch>
                        <Route path="/dashboard" component={Dashboard}/>
                    </Switch>
                </BrowserRouter>
        )
    }
}
export default Router

function Dashboard() {
  return <h1>Dashboard</h1>
}

请更换路由器。如果您这样写,LoginForm 将始终呈现。

import {BrowserRouter, Route, Switch } from "react-router-dom";
import React, {Component} from "react";
import { createBrowserHistory } from "history"

class Routers extends Component {
    render() {
        return (
                <BrowserRouter>
                    <Switch>
                        <Route path="/login" component={LoginForm}/>
                        <Route path="/dashboard" component={Dashboard}/>
                    </Switch>
                </BrowserRouter>
        )
    }
}

问题

您正在创建您的 BrowserRouter 不知道的自定义历史记录对象。 LoginForm 组件正在操纵一个版本的 history 对象,而路由器和路由正在使用路由上下文使用的默认 history 对象。登录表单能够更新地址栏中的 URL,但外部路由上下文无法看到此更改。

解决方案

要么删除自定义历史记录并使用 BrowsserRouter 提供的历史记录,要么使用较低级别的 Router 组件并将自定义 history 对象传递给它以在路由上下文。

使用路由上下文中的标准历史记录

Router.js

<BrowserRouter >
  <LoginForm/>
  <Switch>
    <Route path="/dashboard" component={Dashboard}/>
  </Switch>
</BrowserRouter>

LoginForm - 用 withRouter 高阶组件装饰,以便它从最近的路由上下文接收路由道具。

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

class LoginForm extends Component {

  handleSubmit = (event) => {
    event.preventDefault()
    this.props.history.push("/dashboard")
  }

  render() {
    return (
      <form name="signup_form" onSubmit={this.handleSubmit}>
        <input type="submit" value="Sign Up"/>
      </form>
    );
  }

}

export default withRouter(LoginForm);

使用自定义历史记录

import LoginForm from "./LoginForm";
import { Router, Route, Switch } from "react-router-dom";
import React, { Component } from "react";
import { createBrowserHistory } from "history"

const browserHistory = createBrowserHistory()

class MyRouter extends Component {
  render() {
    return (
      <Router history={browserHistory} >
        <LoginForm />
        <Switch>
          <Route path="/dashboard" component={Dashboard}/>
        </Switch>
      </Router>
    )
  }
}
export default MyRouter;

并且仍然使用 withRouter HOC 装饰 LoginForm,以便传递路由道具。

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

class LoginForm extends Component {

  handleSubmit = (event) => {
    event.preventDefault()
    this.props.history.push("/dashboard")
  }

  render() {
    return (
      <form name="signup_form" onSubmit={this.handleSubmit}>
        <input type="submit" value="Sign Up"/>
      </form>
    );
  }

}

export default withRouter(LoginForm);

建议

正如所写,LoginForm 组件将 始终 呈现,这可能不是您想要的。我建议将它移动到一条路线中,这样路线道具就会被传递。

<Route path="/login" component={LoginForm} />