如何避免CSSTransition模态页切换时组件意外卸载?
解决CSSTransition导致List组件意外卸载的问题
我完全懂你遇到的这个头疼问题——原本切换LoginModal路由时List组件能稳稳留在DOM里,加了CSSTransition后就莫名被卸载了,确实和预期不符。咱们来一步步拆解原因,找到解决方案:
问题根源
你当前的路由结构里,LoginModal的Route和页面路由的Switch被包裹在同一个CSSTransition组件内。当导航到/items/login时:
location.key发生变化,TransitionGroup会判定这是一次全新的路由过渡,直接移除旧的CSSTransition实例(也就是包含List组件的那个)- 新生成的
CSSTransition内部,Switch找不到匹配/items/login的路由,最终渲染NotFound组件,List自然就被彻底卸载了
而不用CSSTransition时,/items/login的Route和/items的Route是独立匹配的——因为/items是前缀路由,/items/login会同时命中path="/items"的Route和/items/login的Route,所以List组件能一直留在DOM中。
解决方案:分离模态框路由与页面过渡
我们需要把模态框的Route从CSSTransition的包裹范围中抽离出来,让页面级路由(List/Item)负责过渡动画,模态框路由单独叠加在页面之上。修改后的路由结构如下:
<TransitionGroup> <CSSTransition key={location.key} classNames="fade" timeout={1000} > <Switch location={location}> <Route exact path="/items/:id([0-9]+)" component={Item} /> <Route path="/items" component={List} /> <Route render={() => <div>Not Found</div>} /> </Switch> </CSSTransition> </TransitionGroup> {/* 将LoginModal的Route移到TransitionGroup外部 */} <Route exact path="/items/login" component={LoginModal} />
为什么这样能解决问题?
- 当导航到
/items/login时,TransitionGroup内部的Switch仍然会匹配path="/items"(前缀匹配规则生效),所以List组件会持续保持挂载状态 LoginModal的Route会独立渲染在页面之上(记得给模态框添加position: fixed类样式实现覆盖效果)- 当在List和Item页面之间切换时,
location.key变化会正常触发CSSTransition的过渡动画,完全不影响原有页面切换的动画效果
额外样式提示
为了让LoginModal正确显示为模态框,需要给它添加基础定位样式:
.LoginModal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; }
这样就能实现模态框叠加在List页面之上,同时List组件再也不会被意外卸载啦!
内容的提问来源于stack exchange,提问作者Thomas Chille
相关产品推荐
相关产品推荐

