SoFunction
Updated on 2025-04-05

About page refresh vuex data disappearing problem solution

VBox is continuing, I feel miserable, is there anyone who can give me a star?

vuex is used for data storage and acts as the same as redux.

I have recently encountered problems during VBox development. When the page is refreshed or closed, the data is reset to zero when the browser is opened again. This is a headache.

Searching online, our solution is to transfer data to localStorage or other persistent storage (such as indexDB).

This is OK. I was in a hurry at the beginning of the design and didn't think about it thoroughly. Now, I can't save every mutation.

This made me very unhappy. I was in the company on Saturday. I was sleepy and I couldn't think of a reasonable solution. I fell asleep in a drowsy way.

After waking up, I initially wanted to use Curry and higher-order functions to solve this problem, but unfortunately there is no correct solution.

Minimize modifications and do not want to move existing codes, the word proxy is the most unreasonable. I remember when I first wrote IBook last time, I also used Proxy to intercept and modify it, and at the same time save data to disk files.

That's right, the solution is ES6's Proxy. After trying it, it's OK.

Source code address:/xiangwenhu/vbox/tree/master/src/utils

There are two questions here

1. Problem with initial value.

2. I want to configure which fields need to be persisted. The data in the store does not mean that I need to be persisted.

First, solve the problem of localStorage storage, because you need to convert strings and simply encapsulate one. Of course, you can also use it./tsironis/lockr , /nbubna/storeOr I wrote the little wheel by myself if you like it.

const ls = 
// /tsironis/lockr
export default {
 getItem(key) {
  try {
   return ((key))
  } catch (err) {
   return null
  }
 },
 setItem(key, val) {
  (key, (val))
 },
 clear() {
  ()
 },
 keys() {
  return ()
 },
 removeItem(key) {
  (key)
 }
}

The second is the simple encapsulation of the agent.

There is still a problem with this version. Now it can only proxy the secondary attributes, which is enough for me now.

createHanlder Creates a proxy for secondary attributes

copy objects, of course you can write more compatible and elegant methods

proxy  Create a proxy for state

import LStorage from './LStorage'

/**
  * Agent secondary attributes
  * @param {*} lsKey The key of localStorage exists
  * @param {*} pk key of first-level attribute
  */
function createHanlder(lsKey, pk) {
 return {
  set: function (target, key, value, receiver) {
   let item = (lsKey)
   if (item && item[pk]) {
    item[pk][key] = value
    (lsKey, item)
   }
   return (target, key, value, receiver)
  }
 }
}

/**
  * Only the data to be stored
  * @param {*} source
  * @param {*} keys
  */
function copy(source, keys = []) {
 if (!source) {
  return source
 }
 let d = (null)
 (k => { d[k] = source[k] })
 return d
}

/**
  * Agent state
  * @param {*} initState Initialized Value
  * @param {*} lsKey localStorage key
  * @param {*} keys The keys that need to be stored
  */
const proxy = function (initState, lsKey, keys = []) {
 let ks = keys, obj = ({}, initState, (lsKey))

 // Agent secondary attributes (k => {
  obj[k] = new Proxy(obj[k], createHanlder(lsKey, k))
 })
 // Save merged values (lsKey, copy(obj, keys))
 return new Proxy(obj, {
  set: function (target, key, value, receiver) {
   (key) >= 0 && (lsKey, copy(target, keys))
   return (target, key, value, receiver)
  }
 })
}

export { proxy }

Calling this side basically has no change, just one more sentencestate = proxy(state, 'playing', ['list'])

import { proxy } from '../utils/LSProxy'
let state = {
 list: [],
 current: null
}
state = proxy(state, 'playing', ['list'])

const mutations = {

 /**
   * Add songs
   * @param {*} state
   * @param {*} song song information
   */
 addSong(state, song) {
  let index = (s =>  === )
  if (index < 0) {
   (song)
  }
 },

 /**
   * Add songs
   * @param {*} state built-in
   * @param {*} songs song list
   */
 addSongs(state, songs) {
  let index = -1
  (song => {
   index = (s =>  === )
   if (index < 0) {
    (song)
   }
  })
 },

 /**
   * Delete songs
   * @param {*} state
   * @param {*} songmid song media id
   */
 removeSong(state, songmid) {
  let index = (s =>  === songmid)
  index >= 0 && (index, 1)
 },

 /**
   * Batch delete songs
   * @param {*} state
   * @param {*} songmids song media list
   */
 removeSongs(state, songmids = []) {
  let index = -1
  (songmid => {
   index = (s =>  === songmid)
   index >= 0 && (index, 1)
  })
 },

 /**
   * Play the next song,
   * @param {*} state
   * @param {*} song is empty
   */
 next(state, song) {
  // If song is not empty, it means it is plugging and playback (provided that it has been added to play)  if (song) {
   let index = (s =>  === )
   if (index >= 0) {
     = [index]
    return
   }
   return
  }
  // If current is empty, it means there is no song played  if (! &&  &&  > 0) {
    = [0]
   return
  }
  // If it is not inserted and current is not empty  if (!song && ) {
   // Is the played song in the current list   let index = (s =>  === )
   // If in the song list, then play the next one   if (index >= 0) {
     = (index ===  - 1 ? [0] : [index + 1])
   } else {
     = [0]
   }
  }
 }
}

export default {
 namespaced: true,
 state,
 mutations
}

The disadvantages of this solution are also very obvious.

1. The code can only be used as a second level, which should be enough for me in general. Flat state

2. The agent's secondary attributes and arrays are automatically modified. If the attributes are modified, the agent will trigger it repeatedly. For example, when 30 songs are added, 30 storage occurs. Of course, I think there are solutions that can be optimized.

I think the advantages are,

1. The data of the state is separated from the synchronization process of localStorage

2. Injection into existing code is quite small.

Of course, there are still problems with my code above.

1. Secondary listening cannot be returned when proxy is executed, because if the default value of the attribute is null/undefined, or if the default value is not set in the initialization, it will not be listened to. It should be placed in the first-level attribute listening and make a judgment.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.

Reference article:

Solve data loss when VUEX is refreshed