开发者问题收集

使用 react-router 检测路由变化

2017-07-28
343268

我必须根据浏览历史记录实现一些业务逻辑。

我想要做的是这样的:

reactRouter.onUrlChange(url => {
   this.history.push(url);
});

当 URL 更新时,有没有办法从 react-router 接收回调?

3个回答

更新至 React Router 5.1+。

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

function SomeComponent() {
  const location = useLocation();

  useEffect(() => {
    console.log('Location changed');
  }, [location]);

  ...
}
onosendi
2020-04-11

尝试检测路由更改时,您可以使用 history.listen() 函数。考虑到您正在使用 react-router v4 ,请使用 withRouter HOC 包装您的组件以访问 history 属性。

history.listen() 返回 unlisten 函数。您可以使用它来 取消注册 监听。

您可以像这样配置您的路线

index.js

ReactDOM.render(
      <BrowserRouter>
            <AppContainer>
                   <Route exact path="/" Component={...} />
                   <Route exact path="/Home" Component={...} />
           </AppContainer>
        </BrowserRouter>,
  document.getElementById('root')
);

然后在 AppContainer.js

class App extends Component {
  
  componentWillMount() {
    this.unlisten = this.props.history.listen((location, action) => {
      console.log("on route change");
    });
  }
  componentWillUnmount() {
      this.unlisten();
  }
  render() {
     return (
         <div>{this.props.children}</div>
      );
  }
}
export default withRouter(App);

来自历史记录 docs

You can listen for changes to the current location using history.listen :

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

The location object implements a subset of the window.location interface, including:

**location.pathname** - The path of the URL
**location.search** - The URL query string
**location.hash** - The URL hash fragment

Locations may also have the following properties:

location.state - Some extra state for this location that does not reside in the URL (supported in createBrowserHistory and createMemoryHistory )

location.key - A unique string representing this location (supported in createBrowserHistory and createMemoryHistory )

The action is one of PUSH, REPLACE, or POP depending on how the user got to the current URL.

当您使用 react-router v3 时,您可以使用 history 包中的 history.listen() ,如上所述,或者您也可以使用 browserHistory.listen()

您可以配置和使用您的路线就像

import {browserHistory} from 'react-router';

class App extends React.Component {

    componentDidMount() {
          this.unlisten = browserHistory.listen( location =>  {
                console.log('route changes');
                
           });
      
    }
    componentWillUnmount() {
        this.unlisten();
     
    }
    render() {
        return (
               <Route path="/" onChange={yourHandler} component={AppContainer}>
                   <IndexRoute component={StaticContainer}  />
                   <Route path="/a" component={ContainerA}  />
                   <Route path="/b" component={ContainerB}  />
            </Route>
        )
    }
} 
Shubham Khatri
2017-07-28

react-router v6

在 react-router v6 中,可以通过组合 useLocationuseEffect 钩子来实现此目的

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

const MyComponent = () => {
  const location = useLocation()

  React.useEffect(() => {
    // runs on location, i.e. route, change
    console.log('handle route change here', location)
  }, [location])
  ...
}

为了方便重用,您可以在自定义 useLocationChange 钩子中执行此操作

// runs action(location) on location, i.e. route, change
const useLocationChange = (action) => {
  const location = useLocation()
  React.useEffect(() => { action(location) }, [location])
}

const MyComponent1 = () => {
  useLocationChange((location) => { 
    console.log('handle route change here', location) 
  })
  ...
}

const MyComponent2 = () => {
  useLocationChange((location) => { 
    console.log('and also here', location) 
  })
  ...
}

如果您还需要在更改时查看上一个路由,可以与 usePrevious 钩子结合使用

const usePrevious = (value) => {
  const ref = React.useRef()
  React.useEffect(() => { ref.current = value })

  return ref.current
}

const useLocationChange = (action) => {
  const location = useLocation()
  const prevLocation = usePrevious(location)
  React.useEffect(() => { 
    action(location, prevLocation) 
  }, [location])
}

const MyComponent1 = () => {
  useLocationChange((location, prevLocation) => { 
    console.log('changed from', prevLocation, 'to', location) 
  })
  ...
}

请务必注意,上述所有内容都会在挂载的 第一个 客户端路由以及后续更改时触发。如果这是个问题,请使用后一个示例,并在执行任何操作之前检查 prevLocation 是否存在。

davnicwil
2020-06-15