react-router keepAlive
m0_67403240 人气:0本文主要介绍了react-router-dom v6 通过outlet实现keepAlive 功能的实现,具体如下:
keepAlive代码:
import React, { useRef, useEffect, useReducer, useMemo, memo } from 'react' import { TransitionGroup, CSSTransition } from 'react-transition-group' import { useLocation } from 'react-router-dom' const KeepAlive = props => { const { include, keys, children } = props const { pathname } = useLocation() const componentList = useRef(new Map()) const forceUpdate = useReducer(bool => !bool)[1] // 强制渲染 const cacheKey = useMemo(() => pathname + "__" + keys[pathname], [pathname, keys]) // eslint-disable-line const activeKey = useRef(null) useEffect(() => { componentList.current.forEach(function(value, key) { const _key = key.split("__")[0] if (!include.includes(_key) || (_key === pathname)) { this.delete(key) } }, componentList.current) activeKey.current = cacheKey if (!componentList.current.has(activeKey.current)) { componentList.current.set(activeKey.current, children) } forceUpdate() }, [cacheKey, include]) // eslint-disable-line return ( <TransitionGroup component={ null }> { Array.from(componentList.current).map(([key, component]) => <CSSTransition key={ key } appear={ true } timeout={ 500 } classNames='fade'> { key === activeKey.current ? <div className={ `layout-container${include.includes(key.split("__")[0]) ? " keep-alive-fade": ""}` }> { component } </div> : <div className='layout-container__keep-alive' style={{ display: 'none' }}> { component } </div> } </CSSTransition> ) } </TransitionGroup> ) } export default memo(KeepAlive)
main.js 中调用
import PropTypes from 'prop-types' import { useLocation, useOutlet } from 'react-router-dom' import { connect } from 'react-redux' import { Layout } from 'antd' import { TransitionGroup, CSSTransition } from 'react-transition-group' import KeepAlive from '@/components/common/keepAlive' import { isKeepAlive } from '@/service/config' const Main = props => { const { fullScreen, cacheRoutes, cacheKeys } = props const outlet = useOutlet() const { pathname } = useLocation() return ( <Layout.Content className={{ "layout-main": true, "full-screen": fullScreen }}> <section> { // isKeepAlive 生产环境中启用缓存 isKeepAlive ? <KeepAlive include={ cacheRoutes } keys={ cacheKeys }> { outlet } // 此处不能用 <Outlet /> 不然无法通过 useRef 来缓存 </KeepAlive> : <TransitionGroup component={ null }> <CSSTransition key={ pathname + cacheKeys[pathname] } appear={ true } timeout={ 500 } classNames='page-fade'> { outlet } // 此处不能用 <Outlet /> 会造成路由切换时,组件重复渲染 </CSSTransition> </TransitionGroup> } </section> </Layout.Content> ) } Main.propTypes = { fullScreen: PropTypes.bool, cacheRoutes: PropTypes.array, cacheKeys: PropTypes.object } const mapStateToProps = state => { return { fullScreen: state.setting.fullScreen, cacheRoutes: state.tabsBar.cacheRoutes, // 需要缓存的路由组件path数组 cacheKeys: state.tabsBar.cacheKeys // 用于组件局部刷新 } } export default connect(mapStateToProps)(Main)
1、当前图片动画中,只设置了第二个标签页缓存,其他的几个未开启缓存,所以可以看到,只有第二个标签页在切回的时候 未重新请求数据。其他标签页每次进入都会重新请求数据。
2、此外这里结合react-transition-group 实现了路由切换的渐隐渐显动画,但需要手动配合css样式控制,不能完全依靠CSSTransition
代码部分:
// 路由进入动画 .fade-enter, .fade-appear { opacity: 0; } .fade-enter-active, .fade-appear-active { opacity: 1; @include transition(opacity .25s cubic-bezier(.645, .045, .355, 1) .25s); } .fade-exit { opacity: 1; z-index: 1; } .fade-exit-active { opacity: 0; z-index: 1; @include transition(opacity .25s cubic-bezier(.645, .045, .355, 1)); } .page-fade-enter, .page-fade-appear { opacity: 0; } .page-fade-enter-active, .page-fade-appear-active { opacity: 1; @include transition(opacity .5s cubic-bezier(.645, .045, .355, 1)); } .page-fade-exit { opacity: 1; display: none!important; } .page-fade-exit-active { opacity: 0; } @keyframes keepAliveFade { 0% { opacity: 0; } 50% { opacity: 0; } 100% { opacity: 1; } } .layout-container { position: absolute; left: 0; right: 0; top: 0; bottom: 0; &.keep-alive-fade { animation: keepAliveFade .5s ease-in-out; } }
加载全部内容