【问题标题】:creating a persistant data hook that supports functions创建一个支持函数的持久数据钩子
【发布时间】:2021-01-22 11:11:53
【问题描述】:

好的,所以我正在创建这个很棒的钩子来保持过滤器状态,现在我的一些过滤器不仅包括可以保存到本地存储然后检索的简单字符串,还包括更复杂的对象,例如在许多情况下包含函数的日期,这个想法是能够存储然后从本地存储中检索这些函数。

这是钩子:

export default function usePersistedState(key, defaultValue) {
  let transformedFuncs = parseWithFunc(localStorage.getItem(key))
  const [state, setState] = React.useState(
    () =>  transformedFuncs || defaultValue
  );
  
  React.useEffect(() => {
      if (key){
        localStorage.setItem(key, stringifyWithFunc(state));
      }
  }, [key, state]);
  return [state, setState];
}

function stringifyWithFunc(obj) {
  return JSON.stringify(obj, function(key, value) {
      return typeof value === "function" ? value.toString() : value;
  });
} 

function parseWithFunc(json) {
  return JSON.parse(json, function(key, value) {
      if (isFunction(key)) {
          return transformFunc(value);
      } else {
          return value; 
      }
  });
}

function isFunction(key) {
  switch (key){
    case "toOption":
      return true
    case "transform":
      return true
    case "validate":
      return true
    default:
      return false
  }
}
function transformFunc(value) {
  return eval(value);
}

现在,由于引用了here 的 JSON.stringify 的 replacer 选项,我成功地对包括函数在内的所有属性进行了字符串化,我还能够使用 reviveroption 来“恢复”我的函数JSON.parse(上面也提到过),问题是我从本地存储中返回的一些函数具有从 webpack 导入的函数(luxon 日期函数),所以我收到以下错误:

Unhandled Rejection (ReferenceError): _utils_common__WEBPACK_IMPORTED_MODULE_11__ is not defined
eval
src/Components/hooks/usePersistedState.js:46
  43 |   }
  44 | }
  45 | function transformFunc(value) {
> 46 |   return eval(value);
  47 | }
  48 | 

问题eval 无法转换或访问_utils_common__WEBPACK_IMPORTED_MODULE_11__ 这只是应用程序中的一个简单共享功能。
我尝试过的事情:我尝试只在本地执行该函数,但仍然出现相同的错误,因为我使用了 luxon 的日期转换函数,我不能简单地自己做。
我不想做的事情:传递我的挂钩回调函数。
我正在寻找一种方法来从本地存储中对我的函数进行水化/再水化,以便我可以继续在应用程序中使用它们。

【问题讨论】:

    标签: javascript json reactjs webpack react-hooks


    【解决方案1】:

    我不确定这会起作用,但我会尝试在 webpack 中将 luxon 设为 external dependency

    // index.html
    <script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/1.25.0/luxon.min.js"></script>
    

    和 那么

    // webpack.config.js
    module.exports = {
    //...
        externals: {
            luxon: 'luxon'
        }
    };
    

    现在,当 webpack 将 'luxon' 作为外部添加时,它不会捆绑 luxon,相反,当您执行 require('luxon')(或者您正在处理导入)时,Webpack 将改为返回全局 luxon。

    理论上,由于该全局将存在于范围内,因此您的再水合函数应该仍然有效。

    【讨论】:

      【解决方案2】:

      所以首先 localstorage 不(不能)知道原始对象是怎样的。您必须显式调用 JSON.parse()。

      yourObject = JSON.parse(localStorage.getItem('yourObject'));
      

      注意

      请注意,JSON 从不支持函数。所以从生成的source code重构函数或原型是不可靠的

      1. 原型未在 JSON 中捕获,并且
      2. 函数可以访问闭包。

      为了获得再水化的对象原型,请按以下方式进行:

      // Profile constructor
      function Profile() {
      
      }
      
      Profile.prototype.isValid = function () {
        return true;
      };
      
      Profile.prototype.isAdmin = function () {
        return this.name === "admin";
      };
      
      // create and serialize your object
      var profile1 = new Profile();
      Profile1.name = "admin";
      
      var copy = JSON.parse(JSON.stringify(Profile1));
      
      // rehydrate with functions on prototype
      var Profile2 = new User();
      for (var prop in copy) {
        if (Object.prototype.hasOwnProperty.call(copy, prop)) {
          ProfileB[prop] = copy[prop];
        }
      }
      
      console.log(ProfileB.isAdmin());

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-18
        • 2011-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多