使用 react-router 检测路由变化
我必须根据浏览历史记录实现一些业务逻辑。
我想要做的是这样的:
reactRouter.onUrlChange(url => {
this.history.push(url);
});
当 URL 更新时,有没有办法从 react-router 接收回调?
更新至 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]);
...
}
尝试检测路由更改时,您可以使用
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
andcreateMemoryHistory
)
location.key
- A unique string representing this location (supported increateBrowserHistory
andcreateMemoryHistory
)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>
)
}
}
react-router v6
在 react-router v6 中,可以通过组合
useLocation
和
useEffect
钩子来实现此目的
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
是否存在。