javascript - 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:
but if I try to use my setFont I have problems (as it is saved in localStorage):
and i got this on 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
I don't know if this is the best logic for this context, if someone can help me.
解决方案
这似乎有点过度设计,并且打乱了一些钩子习语。例如,为钩子返回命名对象对不像数组对那样典型。该set
函数本身很复杂,并返回_setSize
调用的结果。如果使用fontSize
匹配,命名可能会更清晰。setSize
setFontSize
({ 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>
推荐阅读
- azure - 无法创建资源的 Azure 角色
- ajax - 了解ajax POST方法,查找url
- apache-spark - 如何获得 2 个不同的普罗米修斯指标之间的差异?
- mvvmcross - Mvvmcross 6.2.3 viewmodel 导航的奇怪行为
- excel - 是否可以使用 VBA 创建 Excelfiles 的路径?
- reporting-services - 汇总生产报告(静态过滤器)
- javascript - 是否可以通过 npm(而不是 yarn)打包 Electron-builder ?
- docker - nginx + docker:http 到 https 重定向
- symfony - 删除包含 hiddentype 的集合
- nginx - 所有图像的错误 mime 类型 Nginx