Reaction挂钩和本地存储未设置正确的值

sg2wtvxw  于 2022-10-15  发布在  React
关注(0)|答案(2)|浏览(117)

您好,我有一个想法是做一个钩子来增加字体大小并保存本地存储中的首选项。基本上,我有一个从1到4的状态,然后当我单击按钮Add时,我将+1添加到状态中,直到我达到数字4,然后在Remove按钮上,我从状态中删除1,直到1
但我不知道如何将它保存到我的位置,基本上如果我不使用我的useState,只与getInitialValue一起使用,它就能正常工作。

像这个gif一样,如果我手动添加该值,它会起作用:

但如果我尝试使用我的setFont,我会遇到问题(因为它保存在本地存储中):

我在本地存储上看到了这个:

代码:

export default function App() {
  const { fontSize, setSize } = useFontSize();
  console.log(fontSize);
  return (
    <div className="App">
      <button
        onClick={() => {
          setSize(fontSize + 1);
        }}
      >
        add
      </button>
      <button
        onClick={() => {
          setSize(fontSize + 1);
        }}
      >
        remove
      </button>
    </div>
  );
}

挂钩:

export default function useFontSize(defaultSize = { size: 1 }) {
  const [fontSize, _setSize] = useState(getInitialSize);
  function getInitialSize() {
    const savedSize = localStorage.getItem('_size_acessibility_font');
    const parsedSize = JSON.parse(savedSize);
    if (parsedSize) {
      const { size } = parsedSize;
      if (size >= 1 && size <= 4) {
        return size;
      }
    } else {
      return defaultSize.size;
    }
  }

  useEffect(() => {
    console.log(fontSize, 'on useEffect to set on localStorage');
    localStorage.setItem(
      '_size_acessibility_font',
      JSON.stringify({ size: fontSize }),
    );
  }, [fontSize]);

  return {
    fontSize,
    setSize: ({ setSize, ...size }) => {
      console.log(size, 'on function set size');
      if (size > 4) {
        return _setSize(4);
      }
      if (size < 1) {
        return _setSize(1);
      }
      return _setSize(size);
    },
  };
}

示例:
https://codesandbox.io/s/focused-newton-x0mqd
我不知道这是不是最好的逻辑,如果有人能帮我的话。

zqry0prt

zqry0prt1#

这似乎有点过度设计,打乱了一些钩子习惯用法。例如,为挂钩返回命名对象对不如返回数组对典型。set函数本身很复杂,它返回_setSize调用的结果。如果fontSize使用setFontSizesetSize匹配,命名可能会更清楚。
({ setSize, ...size })是有问题的,因为调用方(正确地)提供了一个整数。
以下是修复这些问题的最小完整版本(本地存储被模拟,因为Stack代码段被沙箱保护):

const localStorageMock = (() => {
  const storage = {};
  return {
    getItem: k => storage[k],
    setItem: (k, v) => {storage[k] = v.toString();}
  };
})();

const {useState, useEffect} = React;

const useFontSize = (defaultSize=1) => {
  const clamp = (n, lo=1, hi=4) => Math.min(hi, Math.max(n, lo));
  const clean = n => isNaN(n) ? defaultSize : clamp(+n);
  const storageName = "_size_acessibility_font";
  const fromStorage = clean(localStorageMock.getItem(storageName));
  const [fontSize, setFontSize] = useState(fromStorage);

  useEffect(() => {
    localStorageMock.setItem(storageName, fontSize);
  }, [fontSize]);

  return [fontSize, size => setFontSize(clean(size))];
};

const App = () => {
  const [fontSize, setFontSize] = useFontSize();
  return (
    <div>
      <div>Font size: {fontSize}</div>
      <button onClick={() => setFontSize(fontSize + 1)}>
        +
      </button>
      <button onClick={() => setFontSize(fontSize - 1)}>
        -
      </button>
    </div>
  );
};

ReactDOM.createRoot(document.querySelector("#app"))
  .render(<App />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="app"></div>
68bkxrlz

68bkxrlz2#

useFontSize中,您返回

return {
  fontSize,
  setSize: ({ setSize, ...size }) => {
    console.log(size, 'on function set size');
    if (size > 4) {
      return _setSize(4);
    }
    if (size < 1) {
      return _setSize(1);
    }
    return _setSize(size);
  },
};

然而,在App中,当setSize需要对象时,您只使用一个数字setSize(fontSize + 1);调用setSize
如果将useFontSize更改为返回

return {
  fontSize,
  setSize: (size) => {
    console.log(size, 'on function set size');
    if (size > 4) {
      return _setSize(4);
    }
    if (size < 1) {
      return _setSize(1);
    }
    return _setSize(size);
  },
};

应该能行得通。
请注意,您可能希望清除当前的本地存储,或添加一些错误检查。
还要注意,尽管这只是一个示例,但添加和删除都使用fontSize + 1

相关问题