在后盾我的项目中应用tabs导航是一个重要的性能

上面介绍一下如果配合umi框架和对应的插件实现此性能

参考:react-activation

参考实现:实现一个tabs

目前我的项目用的架构设计是umi3+react17+antd pro5

1.引入应用相干插件

插件地址: umi-plugin-keep-alive

npm install umi-plugin-keep-alive --save# oryarn add umi-plugin-keep-alive

2.公共组件封装
components文件夹下创立KeepAvlieTabs
对应的less款式请自行批改本人的需要

相干的keepAlive与生命周期应用计划及问题请到上述链接react-activation查看

创立index.tsx文件

// /components/KeepAvlieTabs/index.tsximport { useAliveController } from 'react-activation';import { arrayDeduplicate } from '@/utils/Array';import type { CachingNode } from './type';import Tab from './Tab';import styles from './index.less';import { useHistory, useLocation } from 'umi';export default function KeepAliveTabs() {  // history导航  const history = useHistory();  // 本地路由信息  const location = useLocation();  // 获取缓存节点办法和信息  const { getCachingNodes } = useAliveController();  const cachingNodes: CachingNode[] = getCachingNodes();  // 因为是异步组件,须要在这儿解决一下缓存中的反复问题  let nodes: CachingNode[] = arrayDeduplicate(cachingNodes, 'path');  // 首页不参加tabs切换的敞开操作  nodes = nodes.filter((item) => item.path !== '/home');  return (    <ul className={styles['alive-tabs']}>      <li        className={location.pathname === '/home' ? styles.home_active : styles.home_deactive}        onClick={() => {          history.push('/home');        }}      >        <div className="tags-nav">          <span>首页</span>        </div>      </li>      {nodes.map((node) => (        <Tab key={node!.id} node={node} />      ))}    </ul>  );}

创立Tab.tsx文件

// /components/KeepAvlieTabs/Tab.tsximport { useHistory, useLocation } from 'umi';import { useAliveController } from 'react-activation';import { CloseCircleOutlined } from '@ant-design/icons';import type { CachingNode } from './type';import styles from './index.less';export default function Tab({ node }: { node: CachingNode }) {  const history = useHistory();  const location = useLocation();  // 同上,dropScope是开释节点,点删除后删掉以后节点信息  const { getCachingNodes, dropScope } = useAliveController();  const cachingNodes: CachingNode[] | any[] = getCachingNodes();  // 执行tab的删除操作  function dropTab(e: React.MouseEvent<HTMLButtonElement>) {    e.stopPropagation();    // 如果敞开激活中的 KeepAlive Tab,须要先来到以后路由    // 触发 KeepAlive unactivated 后再进行 drop    if (location.pathname === node.path) {      // 路由异步加载管制      const unlisten = history.listen(() => {        setTimeout(() => {          dropScope(node.name as string | RegExp);        }, 30);      });      unlisten();      // 返回排除以后 node 后的最初一个 tab      if (cachingNodes.length <= 1) {        history.push('/');      } else {        const { path } = cachingNodes.filter((item) => item.path !== node.path).pop();        history.push(path);      }    } else {      dropScope(node.name as string | RegExp);    }  }  // 设置以后tab的款式  const className = () => {    if (location.pathname === node.path) {      if (location.pathname === '/home') {        return `${styles.active}  ${styles.home_active}`;      }      return `${styles.active}`;    }    return `${styles.deactive}`;  };    return (    <li      className={className()}      onClick={() => {        history.push(node.path);      }}    >      <div className="tags-nav">        <span>{node.name}</span>        {<CloseCircleOutlined className={styles['close-btn']} onClick={dropTab} />}      </div>    </li>  );}

创立类型文件type.ts

export type CachingNode = {  createTime: number;  updateTime: number;  name?: string;  id: string;  [key: string]: any;};

创立款式less文件

.alive-tabs {  height: 100%;  margin: 0;  padding: 0;  overflow: hidden;  white-space: nowrap;  background: #fff;  li {    position: relative;    display: inline-block;    padding: 0 28px 0 10px;    line-height: 32px;    vertical-align: top;    list-style: none;    border-right: solid 1px #e6e6e6;    cursor: pointer;    transition: background 0.2s;  }  .active {    height: 32px;    background: rgba(#1890ff, 0.1);    border-bottom: 2px solid #1890ff;    // background-color: #42b983;  }  .home_active {    height: 32px;    padding: 0 10px;    background: rgba(#1890ff, 0.1);    border-bottom: 2px solid #1890ff;    // background-color: #42b983;  }  .home_deactive {    padding: 0 10px;  }  .deactive {    background: #fff;  }  .close-btn {    position: absolute;    top: 11px;    right: 10px;    display: flex;    align-items: center;    justify-content: center;    font-size: 12px;    line-height: 0;    outline: none;    // transform: translateY(-50%);  }}

3.在组件中应用keepAlive

创立Books/index.tsx

import React from 'react';import { KeepAlive, useActivate, useUnactivate } from 'react-activation';const Books: React.FC = () => {  return <div>我是被缓存的组件</div>;};export default (props: any) => {  useActivate(()=>{    console.log("我被激活了");  })  useUnactivate(()=>{    console.log("我被缓存了");  })  // 上面应用这样的形式去管制路由操作  // 是为了同步显示路由定义中的title和匹配路由path做对应的操作  // 可依据自行需要批改以后的逻辑  return (    <KeepAlive name={props.route.name} path={props.route.path} saveScrollPosition="screen">      <Books />    </KeepAlive>  );};

4.keepAliveTabs挂载到界面上
咱们的页面布局左高低构造,在app.tsx中,挂载到咱们的头部中,超出显示滚动条,具体的款式和性能请自行添加
未实现鼠标右键菜单敞开所有,左右切换,请自行添加,antd有相干的组件

export const layout: RunTimeLayoutConfig = ({ initialState }: any) => {  return {    // 管制组件是否可缓存    disableMobile: true,    headerContentRender: () => <KeepAliveTabs />,    ...  };};