用于电容器存储的自定义挂钩

Custom hook for Capacitor storage

我正在尝试实现一个自定义挂钩,它通过自动将当前状态值保存在电容器存储中来扩展 useState()。 在这种情况下,我正在努力使用 Capacitor 存储插件的同步功能,这导致我的“自定义状态”实际上是一个承诺:/ 有什么办法可以解决这个问题吗?我已经尝试将 value 初始化为未定义状态,并通过确定初始值来扩展 useCallback。但这没有用。

自定义挂钩:

import { useCallback, useState } from "react";
import { Plugins } from '@capacitor/core';
import { AnyObject } from "../models/SomeModels";
const { Storage } = Plugins;

const APP_NAME = 'de.xxx.yyy';

const getStorage = async(key: string, defaultValue: string|AnyObject) => {
  const { value } = await Storage.get({
    key: `${APP_NAME}.${key}`
  });
  let returnValue;
  try {
    if (value) {
      returnValue = JSON.parse(value);
    };
  } catch(e) {
    returnValue = value;
  };
  return returnValue || defaultValue;
};

export const useStorage = (key: string, defaultValue: string|AnyObject) => {
  const [value, setValue] = useState<string|AnyObject>(async() => await getStorage(key, defaultValue));

  useCallback(() => {
    if (value) {
      let newValue;
      try {
        newValue = JSON.stringify(value);
      } catch(e) {
        newValue = value;
      };
      Storage.set({
        key: `${APP_NAME}.${key}`,
        value: newValue as string
      });
    };
  }, [key, value]);

  return [value, setValue];
};

组件:

[...]
  const [test, setTest] = useStorage('Test', '1');
[...]
  return (
  [...]
    <IonItem>
      <IonLabel>Test</IonLabel>
      <IonInput value={test as string} />
    </IonItem>
[...]

结果:

我从 this blog 得到了这个钩子的想法。

编辑: 通过为 IonInput 添加更改处理程序 (onIonChange={e => setTest(e.detail.value!)}),我发现 setTest 也不起作用。

Dieser Ausdruck kann nicht aufgerufen werden. Es ist kein Bestandteil vom Typ "string | AnyObject" aufrufbar.ts(2349)
const setTest: string | AnyObject

想了又想,午饭后终于搞定了。 我必须将 value 初始化为空状态,将 useCallback 更改为 useEffect 并将空案例添加到我的条件中。
也许有人可以解释,为什么我必须在最后设置 as const

import { useEffect, useState } from "react";
import { Plugins } from '@capacitor/core';
import { AnyObject } from "../models/SomeModels";
const { Storage } = Plugins;

const APP_NAME = 'de.xxx.yyy';

const getStorage = async(key: string, defaultValue: string|AnyObject) => {
  const { value } = await Storage.get({
    key: `${APP_NAME}.${key}`
  });
  let returnValue;
  try {
    if (value) {
      returnValue = JSON.parse(value);
    };
  } catch(e) {
    returnValue = value;
  };
  return returnValue || defaultValue;
};

export const useStorage = (key: string, defaultValue: string|AnyObject) => {
  const [value, setValue] = useState<string|AnyObject>();

  useEffect(() => {
    if (value || typeof value === 'string') {
      let newValue;
      try {
        newValue = JSON.stringify(value);
      } catch(e) {
        newValue = value;
      };
      Storage.set({
        key: `${APP_NAME}.${key}`,
        value: newValue as string
      });
    } else {
      getStorage(key, defaultValue).then(v => setValue(v));
    };
  }, [key, value, defaultValue]);

  return [value, setValue] as const;
};