在项目中有一些关键信息,需要及时更新,比如商城类项目的顶部通栏中的个人账户信息,需要在任何页面下都呈现最新数据,而一般情况下顶部通栏都是公共组件,一次引入各个页面通用。那么怎么在每次路由切换的时候更新数据呢?
我最开始使用的是最暴力的方式,利用 Route 的 render 属性,在路由切换时先更新数据再渲染组件。
<Route
render={props => {
getUserInfo(); // 更新数据的方法
return <Header />
}}
/>
这个方法看似解决了需求的问题,但是有个非常明显的弊端,就是路由每次变化都要重新渲染组件,其实有很多的的渲染是完全没必要的,但是这种情况下并没有办法进行拦截,而且即使是相同的路由,组件也会重新 render 导致进行了没必要的接口请求和组件渲染,一番折腾呵额尝试总结了以下几种更好的路由监听方案。
1. 路由下的内容组件中可以通过 history
对象来进行监听
class Header extends Component {
componentDidMount() {
// 监听路由的变化,如果路由发生变化则进行相应操作
this.props.history.listen(location => {
// 最新路由的 location 对象,可以通过比较 pathname 是否相同来判断路由的变化情况
if (this.props.location.pathname !== location.pathname) {
// 路由发生了变化
}
})
}
}
2. 组件重新渲染前后
class Header extends Component {
componentWillReceiveProps (nextProps, nextState) {
if (this.props.location.pathname !== nextProps.location.pathname){
// 路由发生了变化
}
}
}
同样 componentDidUpdate
、componentWillUpdate
两个生命周期中也是能够去识别出路由变化的。
以上两种方式再结合 shouldComponentUpdate 可以减少组件不必要的渲染
class Header extends Component {
// 当路由发生变化的时候再重新render
shouldComponentUpdate(nextProps) {
let prevRouteName = this.props.location.pathname;
let currentRouteName = nextProps.location.pathname;
return prevRouteName !== currentRouteName;
}
}
3. hooks方式监听
import React, { useEffect } from 'React';
const Header = function (props) {
useEffect(() => {
console.log(props.location);
}, [props.location])
}
export default Header;
其实监听路由最重要的就是监听 props 中 location 对象是否发生了变化,变化了则说明路由改变了,反正则不变。
监听的时机,一种是组件挂载后利用 this.props.history.listen
,另外一种是监听 props 的变化,这包括了 componentWillReceiveProps
、 componentDidUpdate
、componentWillUpdate
,也就是组件接收新的 props,组件将要更新,组件更新完成这几个时间节点,hooks也是一样监听的是 props.location
的变化。
由于是旧项目没有使用 hooks,最终我使用了 this.props.history.listen
+ shouldComponentUpdate
的方式,在新项目中使用 hooks
将会变得更加的简单方便。