防止 react-router history.push 重新加载当前路由

IT技术 javascript reactjs react-router
2021-05-23 02:58:28

我正在迈出我的第一步react-router

我目前正在将hashHistory用于开发目的,并且正在执行“手动”导航。也就是说,我没有使用Link,而是history.push('/some/route');为了导航而调用(响应对锚标记的普通旧点击)。

我注意到的是,即使我已经在目标路由上,react-router每次history.push('/target/route');调用时都会重新渲染相关的目标组件:在每个push('/target/route')

  • URL的片段部分保留 #/target/route
  • URL 的查询字符串部分更改为 ?_k=somethingRandom
  • 目标组件重新渲染

我希望这种重新渲染不会发生 -history.push当我已经在我正在尝试的路线上时,我实际上希望成为一个空操作push

我显然错过了一些东西,因为这不是正在发生的事情。有趣的是,我看到了一些人的帖子,他们试图实现我想摆脱的行为 - 他们想在不离开的情况下“刷新”路线,可以这么说。这看起来很像相反的问题:)。

您能否启发我了解我的误解以及如何实现所需的行为?如果(何时)我切换到,这可能会消失browserHistory吗?

4个回答

我的猜测是您的组件会重新渲染,因为prop当您进行路由器推送时,您所做的更改中的某些内容我怀疑它可能是 的actionkey属性prop.location您始终可以prop在每次渲染期间检查 的所有值以查看发生了哪些变化。

您可以通过将旧路由路径与shouldComponentUpdate生命周期方法中的新路径进行比较来解决此问题如果它没有改变,你就在同一条路线上,你可以通过返回来阻止重新渲染false在所有其他情况下,返回true默认情况下,这始终返回 true。

shouldComponentUpdate: function(nextProps, nextState) {
  if(this.props.route.path == nextProps.route.path) return false;
  return true;
}

您必须进行进一步检查,因为这也将阻止您的组件更新state组件内的更新,但我想这将是您的起点。

shouldComponentUpdate在官方react 文档页面阅读更多信息

当您确定转换到新的 props 和 state 不需要组件更新时,可以使用这个作为返回 false 的机会。

我有同样的问题,我找到了(愚蠢的)解决方案。

您只有一个<button>(默认按钮是type=submit)或类似的东西(表单、提交......等),就像 html 一样重新加载页面<form method=GET ...>

在您的代码中检查它,然后将其删除。

PD: _k=somethingRandom> 这只是您在表单中发送的值输入(或按钮)。

我会试一试...

如果您登陆这里并希望更改您的 URL(例如出于共享目的),那么RR 文档已经提供了所描述的解决方案。只要确保您不使用组件内的历史记录(即this.props.history.push()),因为您将(如预期)路由到目标。但是,您可以访问your浏览器历史记录,而不会干扰组件的history.

以下仅在 Chrome 上测试

// history.js
import { createBrowserHistory } from 'history'
export default createBrowserHistory()

然后从你的 XYZ 组件

// XYZ.js
import React from 'react';
import history from './history'

class XYZ extends React.Component {
    _handleClick() {
        // this should not cause rerender and still have URL change 
        history.push("/someloc");
    }
    render() {
        return(
          <button onClick={this._handleClick.bind(this)}>test </button>
        )
    }
}

希望它可以帮助别人。

我认为更简单的解决方法可能是用我们自己的路线替换路线

import { Route, withRouter } from "react-router-dom";

function MyRoute({ key, path, exact, component: Component, history }) {
  let lastLocation = null;
  return (
    <Route
      key={key}
      path={path}
      exact={exact}
      render={(props) => {
        history.listen((location) => {
          lastLocation = location;
        });

        // monkey patching to prevent pushing same url into history stack
        const prevHistoryPush = history.push;
        history.push = (pathname, state = {}) => {
          if (
            lastLocation === null ||
            pathname !==
              lastLocation.pathname + lastLocation.search + lastLocation.hash ||
            JSON.stringify(state) !== JSON.stringify(lastLocation.state)
          ) {
            prevHistoryPush(pathname, state);
          }
        };
        return <Component {...props} />;
      }}
    />
  );
}

export default withRouter(MyRoute);

我们使用它作为 react-router-dom 实际路由的包装器,它对我来说非常有效。更多请参考这里