Preview 🚀

Abstract

Ant Design, once the number one UI library in the world, has had a significant impact. Ant Design Pro, the official “out-of-the-box mid-platform front-end/Design solution”, is also maturing. Unfortunately, Ant Design Pro did not officially provide the function of page tagging display. Due to the requirements of the environment at that time, I embarked on this road of page tagging…

Key words: Ant Design Pro; Umi; TAB; Page tagging

The introduction

Since my accidental discovery of Ant Design Pro (hereinafter referred to as Pro) in nineteen, it has had an inescapable influence on my technical development. Of course, this paper focuses on my research and implementation of page tagging display. When I first got to know Pro, I was still a rookie who used Java in my work and learned React in my spare time. When I was suddenly faced with a huge scaffolding like Pro (the version of Pro V2 at the time) and had to do a feature THAT I had no idea about, I refused, but I had to do it myself.

The road is rough

It all started with a much-discussed issue in the official warehouse – whether tab-switching mode can be provided. Thanks for the ideas provided by the relevant warehouse. At that time, I studied the source code of several warehouses. There are two main ideas:

  • Read the route configuration to generate a flat route map and inject click event callbacks for other active page components;
  • interceptchildren, the sub-component caches under different routeschildrenAnd then based on the currentlocationRender the corresponding component.

The first idea is to update the rendering of the TAB page by clicking on the event, which is somewhat intrusive to other components. The implementation is not elegant, and more embarrassing is that it does not support the nesting of the page by rendering.

The second idea is not intrusive to other components, just listen for children and location changes. Remember that since hooks were not released at the time, implementing them through class components was cumbersome. Hooks have been refactored into functional component implementations since their release.

The future is bright

The current implementation of Ant Design Pro Plus supports a rich range of features as it has matured over the past two years:

  • Support page nesting routines by rendering
  • Two TAB modes are optional
    • Based on the route, only one TAB page is rendered per route
    • Based on route parameters, hash values of all parameters of each route are calculated, and different hash values render different tabs
  • Can fix the label bar
  • shortcuts
    • Refresh TAB page –window.reloadTab()
    • Close TAB –window.closeTab()
    • Return to previous TAB –window.goBackTab()
    • Close and return to previous TAB –window.closeAndGoBackTab()
  • reloadableTo refresh the current TAB page in the operation bar
  • followA new configuration is added to the route definition. By default, it is added to the end of all the tabs. You can configure this attribute to enable a TAB page in the route definitionfollowOpen after the specified TAB page (refer to query page Demo)
  • persistentTo restore the status of the last TAB page after page refreshing

Thanks to hooks function, it encapsulates the hook of useTabs, and its core functions are clear at a glance. In this way, you only need to render the tabs according to the state.

The core logic

As a function that is not so simple, there are a lot of details that need to be paid attention to. Here are the two core functions.

getOriginalRenderRoute

RenderRoute, the route definition object to be rendered, is resolved according to location and the original route definition. The core is to calculate the correct renderKey, and the uniqueness of the tag page is mainly determined by it (the tag page based on route parameters also needs to be combined with hash value).

const pathnameMapCache: {
  [k: string] :any;
} = {};

function getOriginalRenderRoute(location: H.Location, originalRoutes: MakeUpRoute[]) :RenderRoute {
  const { pathname } = location;

  if (pathnameMapCache[pathname]) {
    return pathnameMapCache[pathname];
  }

  function getMetadata(menuData: MakeUpRoute[], parent: MakeUpRoute | null) :RenderRoute {
    let result: any;

    /** Matches menu items according to the prefix, so the ** level 1 route ** under 'BasicLayout' always finds a combination of 'path' and 'name' */ as long as the 'name' attribute is configured
    const targetRoute = _find(
      menuData,
      (item) = > pathToRegexp(`${item.path}` (. *)).test(pathname) && !! item.name, );/** Write 'result' directly if it is the first level route **, otherwise write 'result' */ only if the parent does not have 'Component'
    if((! parent && targetRoute) || (parent && ! parent.component && targetRoute)) { result = {renderKey: targetRoute.path! . targetRoute, }; }/** If the parent is configured with 'hideChildrenInMenu' and the child is configured with 'name', the result '*/ is overwritten
    if(parent? .hideChildrenInMenu && targetRoute) { result = {renderKey: parent.path! . targetRoute, }; }/** Recursively set 'renderKey' */
    if (Array.isArray(targetRoute? .children) && targetRoute? .children.length) { result = getMetadata(targetRoute! .children! , targetRoute!) || result; }return result;
  }

  const result = getMetadata(originalRoutes, null);

  pathnameMapCache[pathname] = result;
  return result;
}
Copy the code

The comments should be fairly clear, trying to cover as many cases as I can think of. In particular, a cache is made to avoid iterating renderKey calculations.

withRouteTab

Page performance optimization higher-order function. By default, each switch triggers the rendering of all tabs. When too many tabs are opened and the page is complex, there may be significant feedback delays in manipulating the tabs due to unnecessary rendering. This higher-order function can be used to wrap the page components to optimize rendering performance.

A difficult problem

The development of the past two years is not plain sailing. Many problems are neither painful nor itching. One radish and one pit can be solved, but a problem about Umi has tortured me for a long time.

When Umi upgraded to 3.0, I also tried to upgrade the Umi version of the project. When I did not upgrade, I was surprised when I switched, all the tabs would be rendered into the page content corresponding to the current location. At that time, I was shocked and couldn’t help falling into three philosophical questions: Who am I? Where am I? What am I supposed to do?

For quite a long time, I had no clue and also made an issue — “I want to know the similarities and differences between UMI 2 and UMI 3 in the handling of routing components”. I didn’t get any feedback until I felt that I had been left far, far away by UMI. Helpless again crustily skin of head Umi is studied on the routing between two versions rendered source, everything comes to him who waits, finally found, the successful upgrade Umi version, this is also the function only support ^ [email protected] | ^ [email protected].

conclusion

Other known implementations are either broken, less functional, or both. A feature maintenance for nearly two years, the reason why the beginning mentioned “I embarked on the page tagging road of no return” is also this reason, fortunately, now the idea is more and more clear.

It was while writing this article that it occurred to me that it might be a good idea to combine the two ideas mentioned above, that is, only listen to location and remove the children dependency. However, the future focus is likely to be on plug-in integration into Umi.

The front end of the debut encountered Pro, should be a big blessing. On this basis, I have a series of mature understanding of the technology stack of front-end development, and at the same time cultivate good development habits, which also provides a steady stream of power for the subsequent sustainable development of my own technology. Of course, due to the limitations of their own ability, there may be shortcomings in the process, the focus of the Pro page label display is to throw a brick to attract others, if you have any comments or suggestions, welcome criticism and correction.

Dig a hole, the next article seems to have ideas, talk about my front-end reverse entry road, ha ha