Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save turdiyev/76cb130db5910d0b57c67b84f582b9c5 to your computer and use it in GitHub Desktop.
Save turdiyev/76cb130db5910d0b57c67b84f582b9c5 to your computer and use it in GitHub Desktop.
import { useState, useEffect } from 'react';
// Usage
function App() {
// Similar to useState but we pass in a key to value in local storage
// With useState: const [name, setName] = useState('Bob');
const [name, setName] = useLocalStorage('name', 'Bob');
return (
<div>
<input
type="text"
placeholder="Enter your name"
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
);
}
// Hook
function useLocalStorage(key, initialValue) {
// The initialValue arg is only used if there is nothing in localStorage ...
// ... otherwise we use the value in localStorage so state persist through a page refresh.
// We pass a function to useState so localStorage lookup only happens once.
// We wrap in try/catch in case localStorage is unavailable
const [item, setInnerValue] = useState(() => {
try {
return window.localStorage.getItem(key)
? JSON.parse(window.localStorage.getItem(key))
: initialValue;
} catch (error) {
// Return default value if JSON parsing fails
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = value => {
setInnerValue(value);
window.localStorage.setItem(key, JSON.stringify(item));
};
// Alternatively we could update localStorage inside useEffect ...
// ... but this would run every render and it really only needs ...
// ... to happen when the returned setValue function is called.
/*
useEffect(() => {
window.localStorage.setItem(key, JSON.stringify(item));
});
*/
return [item, setValue];
}
@turdiyev
Copy link
Author

turdiyev commented Feb 6, 2019

I think and in my experience, item should be value that inside of JSON.stringify:

const setValue = value => {
    setInnerValue(value);
    window.localStorage.setItem(key, JSON.stringify(value));
  };

@turdiyev
Copy link
Author

turdiyev commented Feb 6, 2019

BTW, If you need typescript code, here you are:

import { useState, Dispatch, SetStateAction } from 'react';


export default function <S>(
    key: string,
    initialValue?: S
): [S, Dispatch<SetStateAction<S>>] {
    // The initialValue arg is only used if there is nothing in localStorage ...
    // ... otherwise we use the value in localStorage so state persist through a page refresh.
    // We pass a function to useState so localStorage lookup only happens once.
    // We wrap in try/catch in case localStorage is unavailable
    const [item, setInnerValue] = useState<S>(() => {
        try {
            const valueItem = window.localStorage.getItem(key);
            return valueItem ? JSON.parse(valueItem) : initialValue;
        } catch (error) {
            // Return default value if JSON parsing fails
            return initialValue;
        }
    });

    // Return a wrapped version of useState's setter function that ...
    // ... persists the new value to localStorage.
    const setValue = (value: SetStateAction<S>): SetStateAction<S> => {
        setInnerValue(value);
        window.localStorage.setItem(key, JSON.stringify(value));
        return value;
    };

    // Alternatively we could update localStorage inside useEffect ...
    // ... but this would run every render and it really only needs ...
    // ... to happen when the returned setValue function is called.
    /*
    useEffect(() => {
      window.localStorage.setItem(key, JSON.stringify(item));
    });
    */

    return [item, setValue];
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment