react-use
react-use copied to clipboard
Fix: fix useLocalStorage func setState to have correct state
Description
Right now the useLocalStorage
hook does not properly add state
as a useCallback
dependency, leading to bugs where you pass a function
as the argument to setState
Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
Checklist
- [x] Read the Contributing Guide
- [x] Perform a code self-review
- [x] Comment the code, particularly in hard-to-understand areas
- [x] Add documentation
- [x] Add hook's story at Storybook
- [x] Cover changes with tests
- [x] Ensure the test suite passes (
yarn test
) - [x] Provide 100% tests coverage
- [x] Make sure code lints (
yarn lint
). Fix it withyarn lint:fix
in case of failure. - [x] Make sure types are fine (
yarn lint:types
).
Your eslint
fails due to configuration changes in prettier@8
which I am guessing happened a while ago but is not tested against.
Spent about an hour trying to setState using callback function, ended up creating my own hook for now
import { useEffect, useState } from 'react';
export default function useLocalstorage<T>(
key: string,
initialVal: T,
): [T, React.Dispatch<React.SetStateAction<T>>] {
const [state, setState] = useState<T>(initialVal);
useEffect(() => {
const localStorageValue = window.localStorage.getItem(key);
if (localStorageValue !== null) {
setState(JSON.parse(localStorageValue));
}
}, [key]);
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(state));
}, [state, key]);
return [state, setState];
}
This is not enough in every case. If something like set(s => s + 1) is called multiple times, before a rerender, it would produce a wrong result, as the old state is used twice.
I believe that instead of using useState
the state
should be kept in a ref thus exposing access to the latest value when needed. Then useUpdate
can be used to trigger renders when the state changes.