Skip to content

vuex-persistedstate 插件源码解读

js
// 一个合并数据的库
import merge from "deepmerge";
// 通过 'a.b.c' 设置对象的 key
import * as shvl from "shvl";

export default function(options, storage, key) {
  // 用户传入的选项
  options = options || {};
  // 优先使用 options.storage。用户未定义就使用 window.localStorage。
  storage = options.storage || (window && window.localStorage);
  // 设置存储时的 key 值。
  key = options.key || "vuex";

  // 测试是否能写入
  function canWriteStorage(storage) {
    try {
      storage.setItem("@@", 1);
      storage.removeItem("@@");
      return true;
    } catch (e) {}

    return false;
  }
	// storage.getItem(key) 获取到值后,再 JSON.parse 进行解析。
  function getState(key, storage, value) {
    try {
      return (value = storage.getItem(key)) && typeof value !== "undefined"
        ? JSON.parse(value)
        : undefined;
    } catch (err) {}

    return undefined;
  }
  // 全部通过筛选
  function filter() {
    return true;
  }
	// storage.setItem(key, state) 保存值。
  function setState(key, state, storage) {
    return storage.setItem(key, JSON.stringify(state));
  }
	// 如果 paths 是一个空数组,就返回整个 state
	// 不是一个空数组,就返回一个对象。
  // 数组比如 ['a.b.c']
  // 返回的对象为 {a:{b:{c:'xxx'}}}
  function reducer(state, paths) {
    return paths.length === 0
      ? state
      : paths.reduce(function(substate, path) {
          return shvl.set(substate, path, shvl.get(state, path));
        }, {});
  }
	// 可以连续使用两次小括号,来进行传参。
  function subscriber(store) {
    return function(handler) {
      // 每次 store 触发 mutation 时,store.subscribe 都会调用 handler。
      return store.subscribe(handler);
    };
  }
  // 如果不能写入,抛出异常
  if (!canWriteStorage(storage)) {
    throw new Error("Invalid storage instance given");
  }
  // 获取本地保存的数据
  const fetchSavedState = () =>
    shvl.get(options, "getState", getState)(key, storage);

  const savedState = fetchSavedState();
  
  return function(store) {
    // 如果有保存的数据
    if (typeof savedState === "object" && savedState !== null) {
      // 调用 store.replaceState 进行合并数据
      store.replaceState(
        // 合并数据
        merge(store.state, savedState, {
          arrayMerge:
            options.arrayMerger ||
            // 如果合并数组类型的数据?
            // 直接替换掉
            function(store, saved) {
              return saved;
            },
          clone: false
        })
      );
      // 对于非 nuxt 项目而言,没有作用。
      (options.rehydrated || function() {})(store);
    }
    // 优先使用用户传入的配置,否则就使用默认的。
    // 使用到高阶函数
    (options.subscriber || subscriber)(store)(function(mutation, state) {
      if ((options.filter || filter)(mutation)) {
        // 直接将整个 store 的 state 进行存储。
        (options.setState || setState)(
          key,
          (options.reducer || reducer)(state, options.paths || []),
          storage
        );
      }
    });
  };
}

Released under the MIT License.