Reputation:
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.
Upvotes: 1
Views: 125
Reputation: 56945
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. Naming could be clearer if fontSize
matched setSize
by using setFontSize
.
({ setSize, ...size })
is problematic since the caller is (correctly) providing an integer.
Here's a minimal, complete version that fixes these issues (local storage is mocked since Stack Snippets is sandboxed):
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>
Upvotes: 1
Reputation: 926
In useFontSize
, you return
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);
when it is expecting an object.
If you change useFontSize
to return
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
Upvotes: 0