Site icon May's Notes

Electron + Zustand 多視窗時資料同步的bug

Electron logo

記錄一下開發過程中遇到的BUG以及原因分析。

發生情境

先描述一下這個BUG發生的情境:

應用有兩個視窗,分別為A,B視窗,我會在A視窗中進行設定,然後實時在B視窗上看到修改。資料使用Zustand保存,修改設定值時會使用ipc event傳給B視窗:

// useDataStore.ts
export const useDataStore = create()(
  persist(
    (set) => ({
      data: {
        title: 'demo',
        size: 'sm',
        color: '#ffffff'
      },
      setData: (newData) => {
        set((state) => {
          window.electron.ipcRenderer.send('UPDATE-DATA', newData)
          return { data: newData }
        })
      },
      setColor: (newColor) => {
        set((state) => {
          // ...略
          return { color: newColor }
        })
      }
      }),
    {
      name: 'data-store',
      storage: createJSONStorage(() => localStorage),
    },
  ),
)

在B視窗中可以接收修改後的state,有些設定值也會在B視窗中進行修改,比如color:

// B視窗
const { setColor } = useDataStore()

useEffect(() => {
  window.electron.ipcRenderer.on(
    'UPDATE-DATA',
    (...args) => {
      const newData = args[0]
      // ...
    }
  )​
  window.electron.ipcRenderer.on(
    'COLOR-CHANGED',
    (...args) => {
      const newColor = args[0]
      setColor(newColor)
    }
  )
}, [setData, setColor])

現在,在A視窗中修改title, size,更新後的data為:

data: {
  title: 'new title',
  size: 'md',
  color: '#ffffff'
}

接著我在B視窗中更改顏色為 #000000,預期更新後的data應為:

data: {
  title: 'new title',
  size: 'md',
  color: '#000000'
}

可實際上更改 color 後 data 為:

data: {
  title: 'demo',
  size: 'sm',
  color: '#000000'
},

可以看出 title, size 變回初始值,只有 color 更新了

發生原因

詢問chatGPT後得到的答案是:

並且 chatGPT 建議的解決方法是:

如果你的 widget 和主視窗資料交互比較多,而且要保持一致,最佳做法是把 state 放在 main process,讓它變成「單一真實資料源」,再透過 IPC 讓多視窗同步,這樣最穩定。

Exit mobile version