前言
- react官方是没给像vue那种keep-alive功能的,网上有些大佬写了些库,里面涉及的东西有点多。我感觉这玩意也可以自己搞个简陋版本,满足自己需要就行。
原理
- react-router在对路由匹配时,不匹配的就直接卸载了。所以为了成为常驻组件,就不能让Route来进行匹配渲染。
- 那么就解决了卸载问题,但又出现3个问题:
- 一、如何控制组件显示与消失?
- 二、如何匹配路由?
- 三、如何解决传值刷新?
- 对于第一个问题,就是你可以进行display的动态切换来进行渲染。并且这样的切换,子组件不会卸载。
- 对于第二个问题,一般来说,我们都会使用connected-react-router的中间件,将history传给它,作为store的状态,这样就可以通过store很方便的取到当前匹配的路径,然后对路径进行判断就可以了。
- 对于第三个问题,其实正常来说,只要有值改变,我们做的keepAlive组件加上里面的子组件全都会刷新,因为使用store一般都会结合connect,当store里面状态发生改变,connect的组件所收到的props就会发生改变,而组件的props改变,会导致组件的刷新。但它确实不会卸载。我们可以通过useEffect加上一个空数组依赖来测试它。
- 当然,为了优化传值,我们可能有必要在KeepAlive组件里对每个子组件需要什么参数进行整理。
代码
- 我通过useEffect加空数组的方法看是否卸载。
function KeepAlive(props:Props) {
console.log(props)
useEffect(()=>{
console.log('我执行了KeepAlive')
},[])
useMemo(()=>({}),[props.cart])
return(
<>
<div style={{display:props.router.location.pathname=='/cart'?'block':'none'}}>
cart
<KKK cart ={props.cart}></KKK>
</div>
<div style={{display:props.router.location.pathname=='/profile'?'block':'none'}}>
profile
</div>
</>
)
}
const mapStateToProps=(state: CombinedState):CombinedState=>(state)
export default connect(mapStateToProps)(KeepAlive)
function Subcop(params:{cart:CartState}) {
console.log('xuanr')
console.log(params.cart)
useEffect(()=>{
console.log('我执行了Subcop')
},[])
return(
<div >xxxxxxxxx</div>
)
}
let KKK = React.memo(Subcop)
- 我顺便试了下,子组件用React.lazy进行懒加载代码分割也是完全ok,只有第一次出现的时候network会飘来脚本,然后就变成常驻组件。