React学习笔记(5)--订阅与发布

React中的通信方式前面用的比较多的是父子通信。通过父组件将参数作为属性传递给子组件。在编写Web3的前端的时候,不可避免的需要连接钱包,并且需要在组件之间共享钱包的signer以及生成的contract。这个时候,可以把登录按钮写到父组件当中去,然后通过父子通信向子组件传参。比如在父组件中定义一个setState,并把这个setState传递到各个子组件。最开始在父组件中并没有调用这个函数,在子组件中调用setState,就会反过来让父组件重新执行一遍。然后把最新的属性传递到各个子组件当中去。

这种方式在不同子页面之间就不太好传递信息了。另外一种方式是通过订阅发布的形式。将需要共享的变量存储在localStorage中。 并将一个回调函数绑定给对象。每次设置对象的值的时候都会触发相应的回调函数。比如set(address,’address’),先向localStorage中存入该地址,然后触发address对应的回调函数,对这个新的address进行新建contract并查询该地址的余额。这样就实现了参数的共享。

订阅与发布一般是写在一个store.js文件中。这个模板是通用的,只需要在主程序中调用subscribe的时候实例化callback函数就可以了。

function setToLocalStorage(key, value) {
  localStorage.setItem(key, JSON.stringify(value));
}
function getFromLocalStorage(key) {
  const value = localStorage.getItem(key);
  return JSON.parse(value);
}
function removeFromLocalStorage(key) {
  localStorage.removeItem(key);
}

function Store() {
  let store = getFromLocalStorage("store") || {};
  let subscriptions = {};

  function get(name) {
    return store[name];
  }

  function set(name, value) {
    store = { ...store, [name]: value };
    setToLocalStorage("store", store);
    if (subscriptions[name] && subscriptions[name].length) {
      subscriptions[name]
        .filter((callback) => callback !== null)
        .forEach((callback) => {
          callback(value);
        });
    }
  }

  function subscribe(name, callback) {
    if (!subscriptions[name]) {
      subscriptions[name] = [];
    }

    const existing = subscriptions[name].find((cb) => cb === callback);
    if (existing) {
      return () => {};
    }

    const length = subscriptions[name].push(callback);
    const index = length - 1;

    return () => {
      subscriptions[name][index] = null;
    };
  }

  function reset() {
    store = {};
    subscriptions = {};
    removeFromLocalStorage("store");
  }

  return { get, set, subscribe, reset };
}

let storeInstance = {};
if (typeof window !== "undefined") {
  storeInstance = Store();
}

const { get, set, subscribe, reset } = storeInstance;

export { get, set, subscribe, reset };

这个store.js来自国产良心NFT项目的开源代码。