Using keepalive to implement navigation tabs in react

Time:2022-1-7

Using tabs navigation in background projects is an important function

The following describes how to implement this function in conjunction with the UMI framework and the corresponding plug-ins

Reference: react activation

Reference implementation: implement a tabs

At present, the architecture design of the project is umi3 + react17 + antd pro5

1. Introduce and use relevant plug-ins

Plug in address: UMI plugin keep alive

npm install umi-plugin-keep-alive --save
# or
yarn add umi-plugin-keep-alive

2. Common component packaging

Create keepavlietabs under the components folder
Please modify your own requirements for the corresponding less style

For relevant keepalive and life cycle usage schemes and problems, please go to the above link react activation

Create index Tsx file

// /components/KeepAvlieTabs/index.tsx
import { 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 navigation
  const history = useHistory();
  //Local routing information
  const location = useLocation();
  //Get cache node method and information
  const { getCachingNodes } = useAliveController();
  const cachingNodes: CachingNode[] = getCachingNodes();
  //Because it is an asynchronous component, you need to deal with the duplication in the cache here
  let nodes: CachingNode[] = arrayDeduplicate(cachingNodes, 'path');
  //The home page does not participate in the closing operation of tabs switching
  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>Front page</span>
        </div>
      </li>
      {nodes.map((node) => (
        <Tab key={node!.id} node={node} />
      ))}
    </ul>
  );
}

Create tab Tsx file

// /components/KeepAvlieTabs/Tab.tsx
import { 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();
  //The same as above. Dropscope is to release the node. Click Delete to delete the current node information
  const { getCachingNodes, dropScope } = useAliveController();
  const cachingNodes: CachingNode[] | any[] = getCachingNodes();
  //Delete tab
  function dropTab(e: React.MouseEvent<HTMLButtonElement>) {
    e.stopPropagation();
    //If you close the keepalive tab in activation, you need to leave the current route first
    //Drop after keepalive deactivated is triggered
    if (location.pathname === node.path) {
      //Route asynchronous load control
      const unlisten = history.listen(() => {
        setTimeout(() => {
          dropScope(node.name as string | RegExp);
        }, 30);
      });
      unlisten();
      //Go to the last tab after excluding the current node
      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);
    }
  }
  //Set the style of the current 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>
  );
}

Create type file type ts

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

Create style less file

.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. Use keepalive in the component

Create books / index tsx

import React from 'react';
import { KeepAlive, useActivate, useUnactivate } from 'react-activation';

const Books: React.FC = () => {
  useActivate(()=>{
    console. Log ("I am activated");
  })
  useUnactivate(()=>{
    console. Log ("I'm cached");
  })
  Return < div > I am a cached component < / div >;
};

export default (props: any) => {
  //The following method is used to control the routing operation
  //This is to synchronously display the title in the route definition and the matching route path
  //You can modify the current logic according to your own needs
  return (
    <KeepAlive name={props.route.name} path={props.route.path} saveScrollPosition="screen">
      <Books />
    </KeepAlive>
  );
};

4. Mount keepalivetabs to the interface

Our page layout has a top left and bottom structure in app In TSX, it is attached to our header, beyond the display of the scroll bar. Please add specific styles and functions by yourself
The right mouse button menu is not implemented. All are closed. Switch left and right. Please add it yourself. Antd has related components

export const layout: RunTimeLayoutConfig = ({ initialState }: any) => {
  return {
    //Controls whether components can be cached
    disableMobile: true,
    headerContentRender: () => <KeepAliveTabs />,
    ...
  };
};

Recommended Today

Springboot 2.6.3 integrated redis stepped on the pit

The integration steps are as follows: development tools: idea2019, JDK1.8, maven 3.5.4 Idea creates a new project, selects spring initializer, selects spring boot version 2.6.3 (the latest version at present), and adds web, and redis modules. After successful construction, the POM file is as follows: <?xml version=”1.0″ encoding=”UTF-8″?> <project xmlns=”http://maven.apache.org/POM/4.0.0″ xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd”> <modelVersion>4.0.0</modelVersion> <parent> […]