This week, I found that VUe-Router cache processing was needed in the development process. The specific scenario is that I need to jump to another page B when FILLING in the form on page A, and click return on page B, so the data on page A will not be lost.

First implementation

Vue-router has its own navigational guard. I use the navigational guard in page A to judge, and use keep-alive and router-view in vue-Router to complete the task. So I happily wrote the following code:

    // A page
  beforeRouteLeave(to, from, next) {
    from.meta.keepAlive = to.name === 'xxxx'; // XXXX represents page B
    next();
  },
 
 / / App. Vue web page<keep-alive> <router-view v-if='$route.meta.keepAlive' /> </keep-alive> <router-view v-if='! $route.meta.keepAlive' />Copy the code

First self-test

When the code is finished, you have to test it locally. Otherwise, if you go to the test environment, you will not be able to write tests against it. On one side of the result, you frown and notice that something is wrong. Outline the steps

  1. I went from page C to page A, wrote A little bit, then quit and went back to page A, and performed as expected (page A was cleared of data). through
  2. On the basis of what I just did (without refreshing), I went to page A to write something, entered page B and then returned to page A. At this time, the data existed and also met the expectation. through

In view of the successful completion of the task, Ben is ready for the next series of Git operations add test. However, based on many experiences, the results of the F5 refresh will be different from the results of the previous operation.

bugs

So I refreshed it on page A (why on page A? Just because I happened to be on page A). Then reverse the steps 1 and 2 above, and the result is the problem.

  • Write data on A page, enter B page, return A page, what is my data, why is missing? It’s all wiped out. I want the data to still be there.

Our test results passed before the refresh, but failed this time, indicating that our code in the navguard is ok (otherwise it would not have been right the first time). When you go to page B for the first time and come back, the data is not saved, and keepAlive is set to true during breakpoint debugging. This is really weird.

Second implementation

Take A look at your code again and again, whether it’s app.vue, Route.js or the code in page A. In route.js, I wrote the route of page A as:

 // Route configuration on page A
  path: 'xxxx'.name: 'APage'.component: AComponent,
  meta: {
    keepAlive: false
  }
Copy the code

I was wondering if I didn’t save the first time because I gave false by default, so I changed the meta object above:

  meta: {
    keepAlive: true
  }
Copy the code

Second self-test

I conducted another test according to the above two tests, and both of them passed. I am very happy, and now I can finally improve the test. Opening the console is an output.

Last implementation

When I thought this solution was perfect, I was tested the next morning at work and said, “You have a problem with this jump cache data.” I wanted to blurt out: “No way, you local clear the cache, your environment has a problem.”

There are bugs left over from the last implementation

As A result, the test conducted an operation in front of me and found that there was no problem with the first operation. In the second operation, there was A problem with the data on page A. The general process was as follows:

  1. First, enter page A on page C, write data on page A and return to page C, enter page A and clear data. through
  2. Enter page A and write data. Enter page B and return to page A. The data still exists. through
  3. In this case, the data is written on page A and then entered on page B. As A result, the data is changed to the data in the second step and the newly written data is missing. GG

It turned out that the opportunistic keepAlive change didn’t work at all, and the bug was still there, just in a different way.

Last implementation

A look at vue-Router’s official website reminds me of another way to implement caching: include and exclude. So I used this scheme to see if I could solve all the problems perfectly:

<! -- // app. vue // keepAliveList is an array of names for all components that you want to cache. / -->
<keep-alive :include="aliveComponent">
  <router-view />
</keep-alive>
Copy the code
// App.vue
import { mapState } from 'vuex'
export default{
  data() {
    return{}},... mapState({aliveComponent: store= > store.aliveComponent
  })
}
Copy the code
// a.vue // Export default {name: 'AComponent', data() { return {} }, beforeRouteLeave(to, from, next) { const status = to.path === 'xxxx'; Use new code.store.mit (updateAliveComponent', {name: 'AComponent', status: status}); next(); }},Copy the code

It turns out that this is still not possible because keepAliveList does not always get the corresponding result immediately after executing next() using the vuex relationship. So I thought of two ways to spend keepAliveList data update time:

// nextTick
// The result indicates failure
this.$nextTick((a)= > {
  next();
});

// setTimeout
// Why use 20? Because I found that the percentage does not necessarily work when there is no value, so I added some time.
setTimeout((a)= > {
  next();
}, 20);

Copy the code

The final code

It has been tested for several times without any problems. In order to prevent similar needs from being optimized in the future, the overall code is as follows:

<! -- // app. vue // keepAliveList is an array of names for all components that you want to cache. -->
<keep-alive :include="keepAliveList">
  <router-view />
</keep-alive>
Copy the code
// App.vue
import { mapState } from 'vuex'
export default{
  data() {
    return{}},... mapState({keepAliveList: _= > _.keepAliveList
  })
}
Copy the code
// A.vue
// The most important thing to remember is to write the component name
export default {
  name: 'AComponent',
  data() {
      return {}
  },
  beforeRouteLeave(to, from, next) {
    const status = to.path === 'xxxx'; // XXXX indicates page B
    this.$store.commit('updateAliveList', { name: 'createRule'.status: status });

    setTimeout((a)= > {
      next();
    }, 20)}},// vuex.js
  state: {
    keepAliveList: []},mutations: {
    updateAliveList(state, { name, status }) {
      if (status) {
        state.keepAliveList.push(name);
      } else {
        const index = state.keepAliveList.indexOf(name);
        index >= 0 && state.keepAliveList.splice(index, 1); }}},Copy the code

conclusion

The biggest drawback to include implementation is that every component that needs to be cached must write a name value, which is cumbersome. At the same time, I added the unstable element of 20ms timer to the navguard, which was not easy to understand and expand. But at present, is a complete set of effective cache scheme, there are more scheme friends can leave a message to discuss.

Github address, there will be more practical blog.