How to copy a Vuex store and import it into a new store

Viewed 195

I am trying to write a way for in Electron to duplicate Vuex commits from one Window to another with IPC. This way devs can use the Vuex store between browser windows seamlessly without manually using IPC calls to send everything, causing lots of duplicate code.

So far, I have written a basic Vue plugin to handle pushing commits around

With only some base code using store.subscribe, I IPC send all commits to main, which then forwards the commits to all renderer windows, applying the commits to their respective stores. Each new browser Windows is able to forward the data to all others. To prevent endless loops, I check the event and payload and verify it's different than the current value before applying it.

This all works. It's not even that slow amazingly. But there is a problem, When the window is opened, the store is fresh. I need a way to export the entire store, IPC it to the new window, and import the store.

Is there any way in Vuex to generically export the entire state, then import it again?

1 Answers

After some time, I found a way to sync vuex store between main window and another IPCRenderer Window. I would not explain how to subscribe to mutation using plugins since the question is about replacing the state. Here are the logic steps to replace the state in newWindow:

  1. When opening a new window from main window, we can call IPCRenderer and send our entire state (this.$store.state)

For example:

this.ipcRenderer.send("open-new-window",cloneObject(this.$store.state));

What we should note here, we could not send a complex object like DOM Object to our new window because you will get circular JSON error, so here I use script (UTIL.cloneObject(this.$store.state)) for convert complex object to avoid circular JSON Error. You can see the code here or you can find in another place since this question is not about converting to circular json

  1. In ipcMain you can store this state in the global variable, for example:
let temporaryState
ipcMain.on('open-new-window', async(event, data) => {
  //Another code...
  newWindow = new BrowserWindow(options);
  temporaryState = data 
   //this is data is your temporary state from mainWindow
  //Another code for open new window
})
  1. Request to rehydrate state in new window if new window already in "mounted stage", for example:
mounted() {
  this.ipcRenderer.send("ask-rehydrate");
}
  1. Back to ipcMain, you can listen to rehydrate request from newWindow and send the state that you already store in global variable, for example:
ipcMain.on('ask-rehydrate', (event) => {
  newWindow.webContents.send("currentState", temporaryState);
}
  1. Listen again in mounted stage to replace the current stage in "newWindow":
mounted() {
  this.ipcRenderer.send("ask-rehydrate");
  this.ipcRenderer.once("currentState", (event, state) => {
       new Promise((resolve, reject) => {
       logger.debug("Current state will be replaced with %o", state);
       this.$store.replaceState(state);
       resolve();
   }).then(() => {
       //Do something});
   });
}

Congratulation now your state in newWindow will replaced with the current state in main window, here the mutation also sync if you subscribe the mutation using plugin. We should do this in mounted stage of vue since we need to wait until the store already initiated.

Related