How to solve the problem of vuex page refresh data loss?

Posted by Rithotyn on Tue, 04 Jan 2022 17:59:51 +0100

1. Problem Description:

Generally, when the login is successful, the user information and menu information need to be placed in vuex as global shared data. However, when the page is refreshed, the data in vuex will be reinitialized, resulting in data loss. Because the data in vuex is saved in the running memory, when the page is refreshed, the page will reload the vue instance, and the data in vuex will be re assigned.

2. Solution:

Method 1: save the data in vuex directly to the browser cache (sessionStorage, localStorage, cookie)

Method 2: when the page is refreshed, request the remote data again to dynamically update vuex data

Method 3: request remote data from the parent page to the background, and save vuex data to sessionStorage before page refresh (in case the amount of requested data is too large, and the returned data cannot be obtained when the page is loaded)

analysis:

The disadvantage of method 1 is that it is unsafe and not suitable for the storage of large amounts of data;

Method 2 applies to a small amount of data without network delay;

Method 3 is the key point, and method 2 is used together with method 1.

3. Solving process: @ 1

3.1. Select appropriate browser storage

localStorage -- it is permanently stored locally unless you take the initiative to delete it;

sessionStorage -- it is stored until the current page is closed and is not associated with other tab pages;

Cookies are stored according to the effective time you set, but the disadvantage is that they cannot store big data and are not easy to read, and will interact with the background.

sessionStorage is selected in this method because vue is a single page application, and all operations jump routes on one page. Another reason is that sessionStorage can ensure that the data of sessionStorage is empty when the page is opened. If it is localStorage, the data of the last page opened will be read.

3.2 solution

Because the data in the state is responsive, the sessionStorage storage also changes, and the values in the state can only be changed through changes.

First, after the user logs in successfully, then the user information and menu information are distributed and saved to vuex through actions. Then calculate the menu data of state in vuex on the menu page, parse and assemble the data into the format required by the front-end components, and then render the components to generate the menu tree. If the page is not refreshed, everything is normal.

After successful login, synchronize user and menu data to vuex

Listen for menu data in vuex on the menu page

Solution for page refresh:

When the page is refreshed, the background data is requested asynchronously, and then the data in vuex is updated dynamically. One of the problems is the network delay and large amount of data. At this time, the page has been loaded before vuex gets the data returned from the background, which will cause data loss. Therefore, the solution is to listen to the events before browser refresh and save the data in vuex to sessionStorage before browser refresh. After successful refresh, if the data requested asynchronously has not been returned, directly obtain the data in sessionStorage, otherwise obtain the data in vuex. (the background data will be retrieved from sessionStorage only if it has not been retrieved after refresh. To ensure the security of the data, even if the data in sessionStorage is obtained, it is safe, because each refresh will re assign the value, so there is no need to worry about the data being tampered with. Secondly, the data in sessionStorage is encrypted.)

When the parent page requests data from the background and listens for events before browser refresh, save vuex data to sessionStorage

Request data from the background on the parent page and distribute the returned data to vuex

3. Solution process: @2 vuex persistedstate

Principle:

Save the state of vuex in localStorage or sessionStorage or a cookie

At the moment of refreshing the page, the vuex data disappears, and vuex will go to sessionStorage to get the data back. In a disguised way, the data refresh is not lost~

usage method:

Installation: NPM install vuex persistedstate -- save

Index. Under store JS, import and configure

import createPersistedState from "vuex-persistedstate"

const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState()]
})

At this time, you can select the location of data storage, which can be localStorage/sessionStorage/cookie. Here, take the storage to sessionStorage as an example, and the configuration is as follows:

import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState({
      storage: window.sessionStorage
  })]
})

Store the specified state:

Vuex persisted state persists all States by default. Specify the States to be persisted. The configuration is as follows:

import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState({
      storage: window.sessionStorage,
      reducer(val) {
          return {
          //Only user s in state are stored
          user: val.user
        }
     }
  })]

At this moment, val corresponds to the contents stored in several js files under the store/modules folder, that is, several modules import ed in the stor/index. You can print and see them yourself. You can configure the name of the data here to store the data permanently. At present, I only want to persist the data of the storage module.

Note: if you want to configure multiple options now, write plugins as a one-dimensional array, otherwise an error will be reported.

import createPersistedState from "vuex-persistedstate"
import createLogger from 'vuex/dist/logger'
//Judgment environment}vuex prompt: not used in production environment
const debug = process.env.NODE_ENV !== 'production'
const createPersisted = createPersistedState({
  storage: window.sessionStorage
})
export default new Vuex.Store({
 // ...
  plugins: debug ? [createLogger(), createPersisted] : [createPersisted]
})

3. Solution process: @3 vuex along

Save a copy of the data in the state to local storage (localStorage, sessionStorage, cookie)

//App.vue

<script>
    export default{
        created() {
            //Read the status information in sessionStorage when the page is loaded
             if (sessionStorage.getItem("store") ) {
                this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(sessionStorage.getItem("store"))))
            }

            //Save the information in vuex to sessionStorage when the page is refreshed
            window.addEventListener("beforeunload",()=>{
                sessionStorage.setItem("store",JSON.stringify(this.$store.state))
            })
        }
    }
</script>

2. Use third-party plug-ins such as vuex along (in essence, it is cached locally using session, etc.)

import Vue from 'vue'
import Vuex from 'vuex'
import VueXAlong from 'vuex-along'
Vue.use(Vuex)
let productData = require('@/assets/api/list.json')

const moduleA = {
    state: {
        a1: 'a1',
        a2: 'a2',
    }
}
export default new Vuex.Store({
    state: {
        productList: [],//List data
        cartList: [],//Shopping cart data
    },
    mutations: {
        //Product list
        setProductList(state, data){
            state.productList = data
        },
        //add to cart
        setCartList(state, id){
            let  cartIndex = state.cartList.findIndex(item => item.id === id)
            if(cartIndex < 0){
                state.cartList.push({id, count: 1})
            }else{
                state.cartList[cartIndex].count++
            }
        },
        //Delete cart item
        deleteCartList(state, id){
            let  cartIndex = state.cartList.findIndex(item => item.id === id)
            state.cartList.splice(cartIndex, 1)
        },
        //Edit cart item quantity
        editCartList(state, data){
            let cartIndex = state.cartList.findIndex(item => item.id === data.id)
            state.cartList[cartIndex].count = data.count
        },
        clearCart(state){
            state.cartList = []
        },
    },
    actions: {
        getProductList(context){
            //Simulate the ajax request and store the returned information directly in the store
            setTimeout(()=>{
                context.commit('setProductList', productData)
            }, 2000)
        },
        buy(context){
            //Simulate an ajax request and return the result to the place where the operation is submitted by returning the promise object
            return new Promise((resolve, reject) => {
                setTimeout(()=>{
                    context.commit('clearCart')
                    resolve({msg:'checkout success ', code: 200})
                    //reject({message: 'Submit failed', code: 300})
                }, 1000)
            })
        }
    },
    modules: {
        ma: moduleA
    },
    //Cache state data to storage
    plugins: [VueXAlong()],
    //Full parameter configuration (sessionStorage data recovery priority is higher than localStorage)
    /* plugins: [VueXAlong({
        // Set the saved collection name to avoid multi project data conflict under the same site
        name: 'my-app-VueXAlong',
        //Filter ma the data and store other data in localStorage
        local: {
            list: ['ma'],//Attribute name or module name to listen to
            isFilter: true,//Filter instead of save
        },
        //Save ma's a1 data to sessionStorage
        session: {
            list: ['ma.a1'],
            isFilter: false,
        },
        //Save using sessionStorage only
        //justSession: true,
    })] */
})

Topics: Javascript Front-end Vue Vue.js