use-local-storage-state
Advanced tools
Comparing version 9.0.2 to 10.0.0
import storage from './storage'; | ||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; | ||
import { useEffect, useMemo, useRef, useState } from 'react'; | ||
export default function useLocalStorageStateBase(key, defaultValue) { | ||
// we don't support updating the `defaultValue` the same way `useState()` doesn't support it | ||
const [defaultValueState] = useState(() => { | ||
const defaultValueForKey = useMemo(() => { | ||
const isCallable = (value) => typeof value === 'function'; | ||
return isCallable(defaultValue) ? defaultValue() : defaultValue; | ||
}); | ||
const getDefaultState = useCallback(() => { | ||
// disabling "exhaustive-deps" on purpose. we don't want to change the default state when | ||
// the `defaultValue` is changed. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [key]); | ||
const defaultState = useMemo(() => { | ||
return { | ||
value: storage.get(key, defaultValueState), | ||
value: storage.get(key, defaultValueForKey), | ||
isPersistent: (() => { | ||
/** | ||
* We want to return `true` on the server. If you render a message based on `isPersistent` and the | ||
* server returns `false` then the message will flicker until hydration is done: | ||
* We want to return `true` on the server. If you render a message based on | ||
* `isPersistent` and the server returns `false` then the message will flicker until | ||
* hydration is done: | ||
* `{!isPersistent && <span>You changes aren't being persisted.</span>}` | ||
@@ -22,2 +25,4 @@ */ | ||
try { | ||
// ulss = use-local-storage-state | ||
// using shorthand to make library smaller in size | ||
localStorage.setItem('__ulss', '#'); | ||
@@ -32,4 +37,4 @@ localStorage.removeItem('__ulss'); | ||
}; | ||
}, [defaultValueState, key]); | ||
const [state, setState] = useState(getDefaultState); | ||
}, [key, defaultValueForKey]); | ||
const [state, setState] = useState(defaultState); | ||
const updateValue = useMemo(() => { | ||
@@ -54,3 +59,3 @@ const fn = (newValue) => { | ||
setState((state) => ({ | ||
value: defaultValueState, | ||
value: defaultValueForKey, | ||
isPersistent: state.isPersistent, | ||
@@ -60,6 +65,4 @@ })); | ||
return fn; | ||
}, [key, defaultValueState]); | ||
/** | ||
* Syncs changes across tabs and iframe's. | ||
*/ | ||
}, [key, defaultValueForKey]); | ||
// syncs changes across tabs and iframe's | ||
useEffect(() => { | ||
@@ -69,3 +72,3 @@ const onStorage = (e) => { | ||
setState({ | ||
value: storage.get(key, defaultValueState), | ||
value: storage.get(key, defaultValueForKey), | ||
isPersistent: true, | ||
@@ -77,8 +80,8 @@ }); | ||
return () => window.removeEventListener('storage', onStorage); | ||
}, [key, defaultValueState]); | ||
/** | ||
* Update the state when the `key` property changes. | ||
*/ | ||
}, [key, defaultValueForKey]); | ||
const isFirstRender = useRef(true); | ||
useEffect(() => { | ||
// set the `defaultValue` in the localStorage on initial render: | ||
// https://github.com/astoilkov/use-local-storage-state/issues/26 | ||
storage.set(key, defaultState.value); | ||
if (isFirstRender.current) { | ||
@@ -88,5 +91,7 @@ isFirstRender.current = false; | ||
} | ||
setState(getDefaultState()); | ||
}, [getDefaultState]); | ||
// update the state when the `key` property changes (not on first render because this will | ||
// cause a second unnecessary render) | ||
setState(defaultState); | ||
}, [key, defaultState]); | ||
return [state.value, updateValue, state.isPersistent]; | ||
} |
{ | ||
"name": "use-local-storage-state", | ||
"version": "9.0.2", | ||
"version": "10.0.0", | ||
"description": "React hook that persist data in local storage. Done right.", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
@@ -5,5 +5,6 @@ # `use-local-storage-state` | ||
[![Build Status](https://travis-ci.org/astoilkov/use-local-storage-state.svg?branch=master)](https://travis-ci.org/astoilkov/use-local-storage-state) | ||
[![Test Coverage](https://api.codeclimate.com/v1/badges/38dfdf48f7f326ccfa8e/test_coverage)](https://codeclimate.com/github/astoilkov/use-local-storage-state/test_coverage) | ||
![Dependencies](https://david-dm.org/astoilkov/use-local-storage-state.svg) | ||
[![Build Status](https://www.travis-ci.com/astoilkov/use-local-storage-state.svg?branch=master)](https://travis-ci.org/astoilkov/use-local-storage-state) | ||
[![Test Coverage](https://img.shields.io/codeclimate/coverage/astoilkov/use-local-storage-state)](https://codeclimate.com/github/astoilkov/use-local-storage-state/test_coverage) | ||
[![Minified Size](https://img.shields.io/npm/dm/use-local-storage-state)](https://www.npmjs.com/package/use-local-storage-state) | ||
[![Minified Size](https://badgen.net/bundlephobia/min/use-local-storage-state)](https://bundlephobia.com/result?p=use-local-storage-state) | ||
@@ -21,10 +22,7 @@ ## Install | ||
- Uses `JSON.parse()` and `JSON.stringify()` to support non string values | ||
- Supports SSR | ||
- SSR support | ||
- 100% test coverage. No `istanbul ignore` | ||
- Handles edge cases – [example](#is-persistent-example) | ||
- Subscribes to the Window [`storage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) event which tracks changes across browser tabs and iframe's | ||
- Small. Controlled by `size-limit`. | ||
- `import { useLocalStorageState } from 'use-local-storage-state'` 1.55 kB | ||
- `import { createLocalStorageState } from 'use-local-storage-state'` 1.5 kB | ||
- High quality with [my open-source principles](https://github.com/astoilkov/me/blob/master/essays/My%20open-source%20principles.md) | ||
- Aiming for high-quality with [my open-source principles](https://astoilkov.com/my-open-source-principles) | ||
@@ -44,2 +42,4 @@ ## Usage | ||
You can experiment with the example [here](https://codesandbox.io/s/todos-example-q48ch?file=/src/App.tsx). | ||
```tsx | ||
@@ -54,2 +54,3 @@ import React, { useState } from 'react' | ||
function onClick() { | ||
setQuery('') | ||
setTodos([...todos, query]) | ||
@@ -176,2 +177,2 @@ } | ||
- [imbhargav5/rooks](https://github.com/imbhargav5/rooks/blob/master/packages/localstorage-state/README.md) | ||
- [dance2die/react-use-localstorage](https://github.com/dance2die/react-use-localstorage) | ||
- [dance2die/react-use-localstorage](https://github.com/dance2die/react-use-localstorage) |
@@ -6,14 +6,17 @@ "use strict"; | ||
function useLocalStorageStateBase(key, defaultValue) { | ||
// we don't support updating the `defaultValue` the same way `useState()` doesn't support it | ||
const [defaultValueState] = react_1.useState(() => { | ||
const defaultValueForKey = react_1.useMemo(() => { | ||
const isCallable = (value) => typeof value === 'function'; | ||
return isCallable(defaultValue) ? defaultValue() : defaultValue; | ||
}); | ||
const getDefaultState = react_1.useCallback(() => { | ||
// disabling "exhaustive-deps" on purpose. we don't want to change the default state when | ||
// the `defaultValue` is changed. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, [key]); | ||
const defaultState = react_1.useMemo(() => { | ||
return { | ||
value: storage_1.default.get(key, defaultValueState), | ||
value: storage_1.default.get(key, defaultValueForKey), | ||
isPersistent: (() => { | ||
/** | ||
* We want to return `true` on the server. If you render a message based on `isPersistent` and the | ||
* server returns `false` then the message will flicker until hydration is done: | ||
* We want to return `true` on the server. If you render a message based on | ||
* `isPersistent` and the server returns `false` then the message will flicker until | ||
* hydration is done: | ||
* `{!isPersistent && <span>You changes aren't being persisted.</span>}` | ||
@@ -25,2 +28,4 @@ */ | ||
try { | ||
// ulss = use-local-storage-state | ||
// using shorthand to make library smaller in size | ||
localStorage.setItem('__ulss', '#'); | ||
@@ -35,4 +40,4 @@ localStorage.removeItem('__ulss'); | ||
}; | ||
}, [defaultValueState, key]); | ||
const [state, setState] = react_1.useState(getDefaultState); | ||
}, [key, defaultValueForKey]); | ||
const [state, setState] = react_1.useState(defaultState); | ||
const updateValue = react_1.useMemo(() => { | ||
@@ -57,3 +62,3 @@ const fn = (newValue) => { | ||
setState((state) => ({ | ||
value: defaultValueState, | ||
value: defaultValueForKey, | ||
isPersistent: state.isPersistent, | ||
@@ -63,6 +68,4 @@ })); | ||
return fn; | ||
}, [key, defaultValueState]); | ||
/** | ||
* Syncs changes across tabs and iframe's. | ||
*/ | ||
}, [key, defaultValueForKey]); | ||
// syncs changes across tabs and iframe's | ||
react_1.useEffect(() => { | ||
@@ -72,3 +75,3 @@ const onStorage = (e) => { | ||
setState({ | ||
value: storage_1.default.get(key, defaultValueState), | ||
value: storage_1.default.get(key, defaultValueForKey), | ||
isPersistent: true, | ||
@@ -80,8 +83,8 @@ }); | ||
return () => window.removeEventListener('storage', onStorage); | ||
}, [key, defaultValueState]); | ||
/** | ||
* Update the state when the `key` property changes. | ||
*/ | ||
}, [key, defaultValueForKey]); | ||
const isFirstRender = react_1.useRef(true); | ||
react_1.useEffect(() => { | ||
// set the `defaultValue` in the localStorage on initial render: | ||
// https://github.com/astoilkov/use-local-storage-state/issues/26 | ||
storage_1.default.set(key, defaultState.value); | ||
if (isFirstRender.current) { | ||
@@ -91,6 +94,8 @@ isFirstRender.current = false; | ||
} | ||
setState(getDefaultState()); | ||
}, [getDefaultState]); | ||
// update the state when the `key` property changes (not on first render because this will | ||
// cause a second unnecessary render) | ||
setState(defaultState); | ||
}, [key, defaultState]); | ||
return [state.value, updateValue, state.isPersistent]; | ||
} | ||
exports.default = useLocalStorageStateBase; |
27419
422
174