All the root causes from the product little sister nonsense demand began

Recently in the development of business projects, the product sister suddenly came to my side, and then on the computer a meal operation, the specific scene is roughly like this.

Scene 1:

As shown in the figure above, when in the tens of thousands of levels of data, select one, click view, jump to the details of the current data page, when click the button to return to return, or the browser forward and back and other operations, return to the list page. To record the current list location. That is, to restore the page before click view view. But when the TAB menu button is clicked, the page information is cleared.

Scene 2:

As shown in the figure above, when we edit the content, some data may be obtained from other pages, so it is required that the editing information of the current page should not be set blank no matter the route is switched or the page is switched. Only when we click OK and reset, the content of the form will be set blank.

Scenario 3: Scenario 1 + Scenario 2 is a more complex scenario for caching page information.

Ii. Carding demand

The keepalive + VUE router function is used in vUE, but the technology stack of our projects is react,react,react. React doesn’t have a built-in Keepalive API for it, and when I did a search on GitHub, I found that there were a lot of things that didn’t fit the business needs. There are also potential risks. Instant panic ~ ~ ~. There is a feeling of ten thousand gods and beasts galloping in my heart.

In front of beautiful product little elder sister, how can say no, that does not appear research and development ability is poor, forcibly installed a wave to say very simple, can only be hard scalp next. Product little sister before leaving also said the ghost smile, said that you can put a few parts of the project page are added to this effect.

1 Solution

1 Data state caching to public management feasibility

First of all, let me think of the demand to the state of the page with redux or mobx cached, then switch a page, the data cache in, switch back again, the data, so it is a problem, even can cache state layer, but if some form components are controlled components cannot be cached, There are also some DOM states that cannot be cached, such as manually added styles. The other thing is that it’s a little more complicated, with rich text components, you can’t get the state of the binding directly.

The second reason is that there are several projects, and more pages, if the establishment of data management, then the workload will be very large. So data state caching is not very feasible, and even if it were possible, it would require a lot of copy-and-paste, which is not what we’re looking for.

2 the react – keepalive – the birth of the router

So we had to choose to develop a project ourselves, open source it, and apply it to a corporate project. Since we choose to cache pages, why not make an article in the Route component and Switch component of the React-Router? We need to do some functional expansion of the Route and Switch components. It’s just that the author has studied the source code of the React-router before. [juejin.cn/post/688629…] The react-router router is a kind of router. Because the project is at the Router level, we have given it the name React-Keepalive-router. The next step is to do a system design for the whole project.

Three design stages

1 understand the react – fiber

Why do we mention react-fiber in our project? Let me first say that React-fiber, which is a rewrite of the Stack Reconciler from the V16 version, is the core algorithm implementation of V16 version. React will generate a fiber tree structure constructed with child pointing to the child fiber,sibling pointing to the brother fiber, and return pointing to the parent fiber during the initial construction process of React. It contains DOM information, update information, props information, etc. Our core idea is: When switching pages, the component is destroyed, but the React Fiber that is scheduled as a render saves the Keepalive state. As long as fiber is alive, you can get dom elements, data layer state, and so on.

2 Based on React-router-DOM and React 16.8

First of all, we need to make changes to the Route and Switch components in the React-Router library. We can implement caching routing through the routing layer. From the beginning of the design, I thought that the keepalive states would be managed in different states. The benefit of this would be to add some additional declaration cycles to the cache routing component, such as activated and deActivated in vUE. Because the design concept is state management, we don’t want to introduce third-party libraries such as Redux in project dependencies, so useReducer in React-hooks is appropriate here. This is one of the reasons why the React base library is 16.8+. Another reason is that there is an API in hooks like useMemo to prevent render penetration, which helps regulate the number of updates to routing components.

Workflow analysis

Inspired by the React-router-cache-Route open source project, I adopted the method of exchanging DOM trees when designing the whole process.

Initialize: The whole idea is that when you first start caching the page, you automatically generate a container component, and the cache Route will give the component to the container component to mount. The container component will then generate a fiber, and then a dom tree will be generated after render to the Route component (our normal page).

Switch pages: When switching pages, the routing component is definitely uninstalled, and we need to return our DOM to the container component, which then freezes.

Switch to the cache page again: When you enter the routing page again, you first discover the cache of the page from the container, then decapsulate the container, and then return the DOM tree to the current routing page. The Keepalive status is complete.

Cache destruction: : This project supports cache destruction. Calling the cache destruction method will uninstall the current cache container and further destroy the fiber and DOM to complete the entire cache destruction function.

Work flow chart

Working schematic diagram

What are the advantages of design?

Design advantages:

1. Because useReducer state management is used to manage the cache state, it can be more flexible, manipulate the cache routing component, adopt the react Hooks API, render throtting, manually remove the cache, increase the cache state cycle, listening function, etc.

This idea of caching pages can be used not only at the level of routing pages, but also at the level of components that can be migrated later. It is also the direction of follow-up maintenance and development.

Introduction to use + Quick to get started

We began to design the usage, API, and application scenarios of the project. Through the above working principle, the function of keepliveRouteSwitch and keepliveRoute in the whole caching process is described.

download

Since we upload the project to NPM for the convenience of other projects, we can download it directly from NPM.

npm install react-keepalive-router --save
# or
yarn add react-keepalive-router
Copy the code

use

1. Basic Usage

KeepaliveRouterSwitch

The KeepaliveRouterSwitch can be understood as either a regular Switch or a keepaliveScope. We ensure that only one KeepaliveRouterSwitch will work for the entire cache scope.

Regular use

import { BrowserRouter as Router, Route, Redirect ,useHistory  } from 'react-router-dom'
import { KeepaliveRouterSwitch ,KeepaliveRoute ,addKeeperListener } from 'react-keepalive-router'

const index = () = > {
  useEffect(() = >{
    /* Add cache listener */
    addKeeperListener((history,cacheKey) = >{
      if(history)console.log('Currently active Cache component:'+ cacheKey )
    })
  },[])
  return <div >
    <div >
      <Router  >
      <Meuns/>
      <KeepaliveRouterSwitch>
          <Route path={'/index'} component={Index} ></Route>
          <Route path={'/list'} component={List} ></Route>{/* We will cache the details page */}<KeepaliveRoute path={'/detail'} component={ Detail } ></KeepaliveRoute>
          <Redirect from='/ *' to='/index' />
       </KeepaliveRouterSwitch>
      </Router>
    </div>
  </div>
}
Copy the code

It should be noted here that ⚠️ is for complex routing structures. If the KeepaliveRouterSwitch package is not a Route, we need to add the KeepaliveRouterSwitch property withoutRoute. The following example is 🌰🌰🌰 :

Example a

<KeepaliveRouterSwitch withoutRoute >
  <div>
     <Route path="/a" component={ComponentA}  />
     <Route path="/b" component={ComponentB}  />
     <KeepaliveRoute path={'/detail'} component={ Detail } ></KeepaliveRoute>
  </div>
</KeepaliveRouterSwitch>

Copy the code

Example 2

Or we can use apis such as renderRoutes in conjunction with KeepliveRouterSwitch.

import {renderRoutes} from "react-router-config"
<KeepliveRouterSwitch withoutRoute  >{ renderRoutes(routes) }</KeepliveRouterSwitch> 
Copy the code

KeepaliveRoute

KeepaliveRoute basic use is no different from Route.

In the current version ⚠️⚠️⚠️ ifKeepaliveRouteIf it’s notKeepaliveRouterSwitchThe package will no longer be cached.

The effect

2 Other Functions

1 The cache component activates the listener

If we want to do something extra for the currently active component, we can add a listener to listen for the activation status of the cached component.

addKeeperListener((history,cacheKey) = >{
  if(history)console.log('Currently active Cache component:'+ cacheKey )
})
Copy the code

The first argument has no history object, and the second argument is a cacheKey that uniquely identifies the current cached route

2 Clearing the Cache

Cached components, or components wrapped by a route, have an additional method cacheDispatch added to props for clearing the cache.

If props does not have a cacheDispatch method, it passes



import React from 'react'
import { useCacheDispatch } from 'react-keepalive-router'

function index(){
    const cacheDispatch = useCacheDispatch()
    return <div>I am a home page<button onClick={()= >CacheDispatch ({type:'reset'})} > Clear the cache</button>
    </div>
}

export default index
Copy the code

1 Clear all caches

cacheDispatch({ type:'reset' }) 
Copy the code

2 Clear a single cache

cacheDispatch({ type:'reset'.payload:'cacheId' }) 
Copy the code

3 Clear multiple caches

cacheDispatch({ type:'reset'.payload: ['cacheId1'.'cacheId2']})Copy the code

Five verification stages

Since it is not appropriate to use a company project here, I used one of my own projects as a demo:

The next step is the verification phase. First, let’s take a look at the first requirement of the product sister:

The second requirement:

Perfect product requirements.

Six packaging phases + release NPM phases

A rollup packaging

And then there’s the rollup packaging phase, the rollup packaging phase. The project structure looks like this.

Rollup.config. js is the configuration file for the entire rollup, and we have the file packaged through rollup stored in the lib folder.

The content of rollup.config.js is as follows

import resolve from 'rollup-plugin-node-resolve'
import babel from 'rollup-plugin-babel'
import { uglify } from 'rollup-plugin-uglify'

export default[{input: 'src/index.js'.output: {
        name: 'keepaliveRouter'.file: 'lib/index.js'.format: 'cjs'.sourcemap: true
      },
      external: [
        'react'.'react-router-dom'.'invariant'].plugins: [
        resolve(),
        babel({
          exclude: 'node_modules/**'}})],/* Compress '*/
    {
      input: 'src/index.js'.output: {
        name: 'keepaliveRouter'.file: 'lib/index.min.js'.format: 'umd'
      },
      external: [
        'react'.'react-router-dom'.'invariant'].plugins: [
        resolve(),
        babel({
          exclude: 'node_modules/**'
        }),
        uglify()
      ]
    }
  ]
Copy the code

Release NPM

For publishing NPM

Step 1: You need to register with NPM. https://www.npmjs.com/signup

Step 2: login to NPM login

Step 3: Create package.json

{
  "name": "react-keepalive-router".Name / * * /
  "version": "1.1.0"./* Version number */
  "description": "The react cache component, based on 'react 16.8+' and 'React-router 4+', can be used to cache page components, similar to 'vue's' keepalive 'package' Vue-router 'effect function.".* / / * description
  "main": "index.js"./* Import file */
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"."build": "rollup --config"
  },
  "keywords": [  /* NPM keyword */
    "keep alive"."react"."react router"."react keep alive route"."react hooks"]."homepage": "https://github.com/GoodLuckAlien/react-keepalive-router"./* Point to github */
  "peerDependencies": { /* NPM projects depend on */
    "react": "> = 16.8"."react-router-dom": "> = 4"."invariant": "> = 2"
  },
  "author": "alien"."license": "ISC"."devDependencies": {  /* The development environment depends on */
    "@babel/core": "^ 7.12.3." "."@babel/preset-react": "^ 7.12.5"."@babel/preset-env": "^ 7.12.1"."@babel/plugin-proposal-class-properties": "^ 7.12.1"."rollup": "^ 2.33.3"."rollup-plugin-node-resolve": "^ 5.2.0." "."rollup-plugin-babel": "^ 4.4.0"."rollup-plugin-uglify": "^ 6.0.4"
  },
  "dependencies": { /* The production environment depends on */
    "invariant": "^ 2.2.4." "}}Copy the code

Step 4: When everything is ready, publish with NPM Publish.

Step 5: Upgrade the version, the upgrade version is very simple, we need to upgrade the version number in package.json, and then re-npm publish.

Obsolete version number

If we want to deprecate a version, run NPM deprecate < PKG >[@

]

Waste package

If we want to scrap package NPM unpublish < PKG > –force

.npmignore

Npmignore: files and their values will not be uploaded to NPM. For my project, except for readme.md,package.json and files packaged under lib, most of the files will be used during development or compilation, so I don’t need to upload them to NPM. So I’m going to write this in.npmignore

docs
node_modules
src
md
.babelrc
.gitignore
.npmignore
.prettierrc
rollup.config.js
yarn.lock
Copy the code

Seven summarizes

The project address

react-keepalive-router

After running through the process from requirements to open source, I will have a great sense of achievement. My independent development project must have a lot of bugs at the beginning. I am not afraid of bugs, and I should have the courage to fix bugs and maintain the project.

Send roses, hand left fragrance, reading friends can give the author ** like, attention a wave. ** Keep updating the front end articles.

Feel useful friends can follow the author public account front-end Sharing continue to update the front-end article.

If you like me, you can vote for me. The poster is as follows: 🙏🙏🙏 thank you