首页 > 解决方案 > 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

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.

like this gif, If I add the value manually it works:

enter image description here

but if I try to use my setFont I have problems (as it is saved in localStorage):

enter image description here

and i got this on localStorage :

enter image description here

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

I don't know if this is the best logic for this context, if someone can help me.

标签: javascriptreactjsreact-hooks

解决方案


这似乎有点过度设计,并且打乱了一些钩子习语。例如,为钩子返回命名对象对不像数组对那样典型。该set函数本身很复杂,并返回_setSize调用的结果。如果使用fontSize匹配,命名可能会更清晰。setSizesetFontSize

({ setSize, ...size })是有问题的,因为调用者(正确地)提供了一个整数。

这是修复这些问题的最小完整版本(由于 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>


推荐阅读