V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
travisyang
V2EX  ›  Electron

使用 useLocalStorage 实现 electron、网页多窗口 state 同步

  •  
  •   travisyang ·
    wxydev1 · 2023-03-15 15:31:39 +08:00 · 1638 次点击
    这是一个创建于 648 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前几天发了一个帖子关于如何实现 electron 多窗口开发,发现思路有点问题。今天又想到了可以用 localStorage+hook 的方式。浏览器 window 可以监听 storage 的变化。并用 mobx 来管理状态,当状态值发生变化的时候,往 localStorage 中写入新的序列化后的值。

    有评论区大哥说可以封装一个 ipc 的 proxy 。 但是我觉得 ipc 这玩意还是太过复杂,不如把所有的逻辑都放在渲染进程写。

    hook 代码

    import { autorun, observable } from "mobx";
    import { useEffect } from "react";
    
    export const useLocalStorage = <T>(storageKey: string, fallbackState: T) => {
      const state = observable({
        value: JSON.parse(localStorage.getItem(storageKey)) ?? fallbackState,
      });
    
      autorun(() => {
        localStorage.setItem(storageKey, JSON.stringify(state.value));
      });
      const onStorageUpdate = (e) => {
        const { key, newValue } = e;
        state.value = JSON.parse(newValue);
      };
      useEffect(() => {
        localStorage.setItem(storageKey, JSON.stringify(state.value));
        window.addEventListener("storage", onStorageUpdate);
    
        return () => {
          window.removeEventListener("storage", onStorageUpdate);
        };
      }, [state.value, storageKey]);
    
      return [state.value];
    };
    
    

    主窗口

    const App = observer(() => {
      const [store, setStore] = useLocalStorage("store", countStore);
      return (
        <div>
          <h1>I am Main Window</h1>
          <button
            onClick={() => {
              const win = window.open("child.html");
            }}
          >
            Open Child Window
          </button>
          <div>store.count = {store.count}</div>
          <button
            onClick={() => {
              store.count--;
            }}
          >
            minus-
          </button>
          <button
            onClick={() => {
              store.count++;
            }}
          >
            plus+
          </button>
        </div>
      );
    });
    

    子窗口

    const Child = observer(() => {
      const [store, setStore] = useLocalStorage('store', null);
    
      return (
        <div>
          <h1 onClick={() => {
            store.count ++
          }}>I am Child Window</h1>
          <div>store.count = {store.count}</div>
        </div>
      );
    });
    

    效果图

    效果图

    demo 链接:

    https://github.com/wxydev1/electron-sync-state

    6 条回复    2023-04-19 10:50:03 +08:00
    zsj1029
        1
    zsj1029  
       2023-03-15 16:41:25 +08:00
    ruxuan1306
        2
    ruxuan1306  
       2023-03-15 16:51:59 +08:00
    思路有意思学习了。但看起来 useLocalStorage 少返回一个 setStore ,我猜是引入 mobx 后例程忘改了。
    travisyang
        3
    travisyang  
    OP
       2023-03-15 17:13:37 +08:00
    @ruxuan1306 确实少返回了一个 setStore ,不过 mobx 支持直接修改成员变量触发 ui 更新,所以返回一个值也够了
    travisyang
        4
    travisyang  
    OP
       2023-03-15 17:13:59 +08:00
    @zsj1029 是的
    snowKing66
        5
    snowKing66  
       2023-04-19 09:45:15 +08:00
    思路很棒,但是如果要实际运用到工程项目中,我还有点疑问,如果采用这种方式作为窗口通信,不知道效率上跟 ipc 相比如何?因为安全性方便应该是不如 ipc
    travisyang
        6
    travisyang  
    OP
       2023-04-19 10:50:03 +08:00
    @snowKing66 效率上还没考虑过。其实用 ipc 的话也可以用同样的方式封装成一个 hook 。我一开始只是觉得 ipc 太麻烦了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   946 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 22:49 · PVG 06:49 · LAX 14:49 · JFK 17:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.