我有几个按钮作为路径。每次改变路线时,我都想确保激活的按钮发生了变化。

有没有办法在react路由器v4中监听路由变化?


当前回答

您应该使用history v4 lib。

这里的例子

history.listen((location, action) => {
  console.log(`The current URL is ${location.pathname}${location.search}${location.hash}`)
  console.log(`The last navigation action was ${action}`)
})

其他回答

我使用withRouter来获取位置道具。当组件因为一个新的路由而更新时,我检查值是否发生了变化:

@withRouter
class App extends React.Component {

  static propTypes = {
    location: React.PropTypes.object.isRequired
  }

  // ...

  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      this.onRouteChanged();
    }
  }

  onRouteChanged() {
    console.log("ROUTE CHANGED");
  }

  // ...
  render(){
    return <Switch>
        <Route path="/" exact component={HomePage} />
        <Route path="/checkout" component={CheckoutPage} />
        <Route path="/success" component={SuccessPage} />
        // ...
        <Route component={NotFound} />
      </Switch>
  }
}

要在上面的基础上展开,您需要获取history对象。如果您正在使用BrowserRouter,您可以导入withRouter并使用高阶组件(HoC)包装您的组件,以便通过道具访问历史对象的属性和函数。

    import { withRouter } from 'react-router-dom';

    const myComponent = ({ history }) => {

        history.listen((location, action) => {
            // location is an object like window.location
            console.log(action, location.pathname, location.state)
        });

        return <div>...</div>;
    };

    export default withRouter(myComponent);

唯一需要注意的是,使用throuter和大多数其他访问历史的方法似乎会污染道具,因为它们将对象解构到其中。

正如其他人所说,这已经被react路由器暴露的钩子所取代,并且它有内存泄漏。如果你在一个函数组件中注册监听器,你应该通过useEffect来做,然后在函数的返回中取消注册。

您应该使用history v4 lib。

这里的例子

history.listen((location, action) => {
  console.log(`The current URL is ${location.pathname}${location.search}${location.hash}`)
  console.log(`The last navigation action was ${action}`)
})

我刚刚处理了这个问题,所以我将把我的解答作为其他答案的补充。

这里的问题是useEffect并没有像您希望的那样工作,因为调用只在第一次呈现之后才被触发,因此存在不必要的延迟。 如果您使用一些状态管理器,如redux,您很可能会在屏幕上看到闪烁,因为存储中存在持续的状态。

你真正想要的是使用uselayouteeffect,因为它会立即被触发。

所以我写了一个小的实用函数,我把它放在和路由器相同的目录中:

export const callApis = (fn, path) => {
    useLayoutEffect(() => {
      fn();
    }, [path]);
};

我从组件HOC中调用它,如下所示:

callApis(() => getTopicById({topicId}), path);

path是使用withRouter时在match对象中传递的道具。

我真的不赞成手动地听/不听历史。 这只是我的看法。

用钩子:

import { useEffect } from 'react'
import { withRouter } from 'react-router-dom'
import { history as historyShape } from 'react-router-prop-types'

const DebugHistory = ({ history }) => {
  useEffect(() => {
    console.log('> Router', history.action, history.location)
  }, [history.location.key])

  return null
}

DebugHistory.propTypes = { history: historyShape }

export default withRouter(DebugHistory)

导入并呈现为<DebugHistory>组件