简体   繁体   English

React Hooks 和 localStorage 没有设置正确的值

[英]React Hooks and localStorage dont set correct value

Hello I had an idea to make a hook to increase the font size and save preferences in localStorage basically I have a state that goes from 1 to 4, and then when I click the button add I add +1 to the state until I reach number 4 and on the remove button I remove 1 from the state until 1你好,我有一个想法,做一个钩子来增加字体大小并在 localStorage 中保存首选项基本上我有一个从 1 到 4 的状态,然后当我单击按钮添加时,我将 +1 添加到状态,直到我达到数字4 在删除按钮上,我从状态中删除 1 直到 1

But I have doubts on how to save this to my location basically if i don't use my useState just with getInitialValue It works normally.但是,如果我不将 useState 仅与 getInitialValue 一起使用,我对如何将其保存到我的位置存有疑问,它可以正常工作。

like this gif, If I add the value manually it works:像这个 gif,如果我手动添加值,它会起作用:

在此处输入图片说明

but if I try to use my setFont I have problems (as it is saved in localStorage):但是如果我尝试使用我的 setFont 我有问题(因为它保存在 localStorage 中):

在此处输入图片说明

and i got this on localStorage :我在 localStorage 上得到了这个:

在此处输入图片说明

code:代码:

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>
  );
}

hook:钩:

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);
    },
  };
}

example:例子:

https://codesandbox.io/s/focused-newton-x0mqd https://codesandbox.io/s/focused-newton-x0mqd

I don't know if this is the best logic for this context, if someone can help me.如果有人可以帮助我,我不知道这是否是这种情况的最佳逻辑。

This seems a tad overengineered and upsets a few hooks idioms.这似乎有点过度设计并扰乱了一些钩子习语。 For example, returning a named object pair for a hook is less typical than an array pair.例如,为钩子返回命名对象对不像数组对那么典型。 The set function itself is complex and returns the result of the _setSize calls. set函数本身很复杂,并返回_setSize调用的结果。 Naming could be clearer if fontSize matched setSize by using setFontSize .如果fontSize通过使用setFontSizesetSize匹配,则命名可能会更清晰。

({ setSize, ...size }) is problematic since the caller is (correctly) providing an integer. ({ setSize, ...size })是有问题的,因为调用者(正确地)提供了一个整数。

Here's a minimal, complete version that fixes these issues (local storage is mocked since Stack Snippets is sandboxed):这是修复这些问题的最小完整版本(本地存储被模拟,因为 Stack Snippets 是沙盒的):

 <script type="text/babel" defer> 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.render(<App />, document.body); </script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

In useFontSize , you returnuseFontSize ,您返回

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);
  },
};

However, in App , you call setSize with just a number setSize(fontSize + 1);然而,在App ,你可以调用setSize只是一个数量setSize(fontSize + 1); when it is expecting an object.当它期待一个对象时。

If you change useFontSize to return如果您更改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);
  },
};

It should work.它应该工作。

Note, you will want to clear your current local storage, or add some error checking.请注意,您需要清除当前的本地存储,或添加一些错误检查。

Also note, although it is just an example, both add and remove use fontSize + 1还要注意,虽然这只是一个例子,但 add 和 remove 都使用fontSize + 1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM