Skip to content

Commit 973a11f

Browse files
committed
chore: 🤖 catch up with master
2 parents 6575b14 + 9439982 commit 973a11f

21 files changed

+1272
-728
lines changed

CHANGELOG.md

+47
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,50 @@
1+
# [13.19.0](https://github.com/streamich/react-use/compare/v13.18.0...v13.19.0) (2020-01-16)
2+
3+
4+
### Features
5+
6+
* add useError hook ([65f3644](https://github.com/streamich/react-use/commit/65f364420524bacebe8f8149b8197fb62bff1a08))
7+
8+
# [13.18.0](https://github.com/streamich/react-use/compare/v13.17.0...v13.18.0) (2020-01-16)
9+
10+
11+
### Bug Fixes
12+
13+
* check for null ([d619c39](https://github.com/streamich/react-use/commit/d619c39a21e9f0b4b4bfc6a209311bf0bd495f9b))
14+
15+
16+
### Features
17+
18+
* add serializer/deserializer option to useLocalStorage ([5316510](https://github.com/streamich/react-use/commit/5316510babf7606a2f4b78de2b0eb85c930890cf))
19+
20+
# [13.17.0](https://github.com/streamich/react-use/compare/v13.16.1...v13.17.0) (2020-01-15)
21+
22+
23+
### Features
24+
25+
* add support for body lock on iOS ([d778408](https://github.com/streamich/react-use/commit/d7784084fe84aca72efe85260101b00ef1df7580))
26+
27+
## [13.16.1](https://github.com/streamich/react-use/compare/v13.16.0...v13.16.1) (2020-01-14)
28+
29+
30+
### Bug Fixes
31+
32+
* update the types dep for js-cookie ([5c55d59](https://github.com/streamich/react-use/commit/5c55d59a7d1d799cba7af87e15ab4a4b27a8fc67))
33+
34+
# [13.16.0](https://github.com/streamich/react-use/compare/v13.15.0...v13.16.0) (2020-01-14)
35+
36+
37+
### Features
38+
39+
* add option to useTitle to restore title on un-mount ([b8b3e47](https://github.com/streamich/react-use/commit/b8b3e479cea6071d4310bac29f138bd8917eee0b))
40+
41+
# [13.15.0](https://github.com/streamich/react-use/compare/v13.14.3...v13.15.0) (2020-01-13)
42+
43+
44+
### Features
45+
46+
* add useCookie hook ([4e5c90f](https://github.com/streamich/react-use/commit/4e5c90f021f56ae2008dc25daad69c43063f608f))
47+
148
## [13.14.3](https://github.com/streamich/react-use/compare/v13.14.2...v13.14.3) (2020-01-08)
249

350

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@
9595
- [**Side-effects**](./docs/Side-effects.md)
9696
- [`useAsync`](./docs/useAsync.md), [`useAsyncFn`](./docs/useAsyncFn.md), and [`useAsyncRetry`](./docs/useAsyncRetry.md) — resolves an `async` function.
9797
- [`useBeforeUnload`](./docs/useBeforeUnload.md) — shows browser alert when user try to reload or close the page.
98+
- [`useCookie`](./docs/useCookie.md) — provides way to read, update and delete a cookie. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usecookie--demo)
9899
- [`useCopyToClipboard`](./docs/useCopyToClipboard.md) — copies text to clipboard.
99100
- [`useDebounce`](./docs/useDebounce.md) — debounces a function. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-usedebounce--demo)
101+
- [`useError`](./docs/useError.md) — error dispatcher. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/side-effects-useerror--demo)
100102
- [`useFavicon`](./docs/useFavicon.md) — sets favicon of the page.
101103
- [`useLocalStorage`](./docs/useLocalStorage.md) — manages a value in `localStorage`.
102104
- [`useLockBodyScroll`](./docs/useLockBodyScroll.md) — lock scrolling of the body element.
@@ -150,7 +152,6 @@
150152
- [**Miscellaneous**]()
151153
- [`useEnsuredForwardedRef`](./docs/useEnsuredForwardedRef.md) and [`ensuredForwardRef`](./docs/useEnsuredForwardedRef.md) — use a React.forwardedRef safely. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-useensuredforwardedref--demo)
152154

153-
154155
<br />
155156
<br />
156157
<br />

docs/useCookie.md

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# `useCookie`
2+
3+
React hook that returns the current value of a `cookie`, a callback to update the `cookie`
4+
and a callback to delete the `cookie.`
5+
6+
## Usage
7+
8+
```jsx
9+
import { useCookie } from "react-use";
10+
11+
const Demo = () => {
12+
const [value, updateCookie, deleteCookie] = useCookie("my-cookie");
13+
const [counter, setCounter] = useState(1);
14+
15+
useEffect(() => {
16+
deleteCookie();
17+
}, []);
18+
19+
const updateCookieHandler = () => {
20+
updateCookie(`my-awesome-cookie-${counter}`);
21+
setCounter(c => c + 1);
22+
};
23+
24+
return (
25+
<div>
26+
<p>Value: {value}</p>
27+
<button onClick={updateCookieHandler}>Update Cookie</button>
28+
<br />
29+
<button onClick={deleteCookie}>Delete Cookie</button>
30+
</div>
31+
);
32+
};
33+
```
34+
35+
## Reference
36+
37+
```ts
38+
const [value, updateCookie, deleteCookie] = useCookie(cookieName: string);
39+
```

docs/useError.md

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# `useError`
2+
3+
React side-effect hook that returns an error dispatcher.
4+
5+
## Usage
6+
7+
```jsx
8+
import { useError } from 'react-use';
9+
10+
const Demo = () => {
11+
const dispatchError = useError();
12+
13+
const clickHandler = () => {
14+
dispatchError(new Error('Some error!'));
15+
};
16+
17+
return <button onClick={clickHandler}>Click me to throw</button>;
18+
};
19+
20+
// In parent app
21+
const App = () => (
22+
<ErrorBoundary>
23+
<Demo />
24+
</ErrorBoundary>
25+
);
26+
```
27+
28+
## Reference
29+
30+
```js
31+
const dispatchError = useError();
32+
```
33+
34+
- `dispatchError` &mdash; Callback of type `(err: Error) => void`

docs/useLocalStorage.md

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22

33
React side-effect hook that manages a single `localStorage` key.
44

5-
65
## Usage
76

87
```jsx
9-
import {useLocalStorage} from 'react-use';
8+
import { useLocalStorage } from 'react-use';
109

1110
const Demo = () => {
1211
const [value, setValue, remove] = useLocalStorage('my-key', 'foo');
@@ -22,15 +21,21 @@ const Demo = () => {
2221
};
2322
```
2423

25-
2624
## Reference
2725

2826
```js
2927
useLocalStorage(key);
3028
useLocalStorage(key, initialValue);
31-
useLocalStorage(key, initialValue, raw);
29+
useLocalStorage(key, initialValue, { raw: true });
30+
useLocalStorage(key, initialValue, {
31+
raw: false,
32+
serializer: (value: T) => string,
33+
deserializer: (value: string) => T,
34+
});
3235
```
3336

3437
- `key` &mdash; `localStorage` key to manage.
3538
- `initialValue` &mdash; initial value to set, if value in `localStorage` is empty.
3639
- `raw` &mdash; boolean, if set to `true`, hook will not attempt to JSON serialize stored values.
40+
- `serializer` &mdash; custom serializer (defaults to `JSON.stringify`)
41+
- `deserializer` &mdash; custom deserializer (defaults to `JSON.parse`)

package.json

+18-14
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@
4646
},
4747
"homepage": "https://github.com/streamich/react-use#readme",
4848
"dependencies": {
49+
"@types/js-cookie": "2.2.4",
4950
"@xobotyi/scrollbar-width": "1.5.0",
5051
"copy-to-clipboard": "^3.2.0",
5152
"fast-shallow-equal": "^1.0.0",
53+
"js-cookie": "^2.2.1",
5254
"nano-css": "^5.2.1",
5355
"react-fast-compare": "^2.0.4",
5456
"react-universal-interface": "^0.6.0",
@@ -64,22 +66,22 @@
6466
"react-dom": "^16.8.0"
6567
},
6668
"devDependencies": {
67-
"@babel/core": "7.8.0",
68-
"@babel/plugin-syntax-dynamic-import": "7.8.0",
69-
"@babel/preset-env": "7.8.0",
70-
"@babel/preset-react": "7.8.0",
71-
"@babel/preset-typescript": "7.8.0",
69+
"@babel/core": "7.8.3",
70+
"@babel/plugin-syntax-dynamic-import": "7.8.3",
71+
"@babel/preset-env": "7.8.3",
72+
"@babel/preset-react": "7.8.3",
73+
"@babel/preset-typescript": "7.8.3",
7274
"@semantic-release/changelog": "3.0.6",
7375
"@semantic-release/git": "7.0.18",
7476
"@semantic-release/npm": "5.3.5",
7577
"@shopify/jest-dom-mocks": "2.8.8",
76-
"@storybook/addon-actions": "5.3.1",
77-
"@storybook/addon-knobs": "5.3.1",
78-
"@storybook/addon-notes": "5.3.1",
79-
"@storybook/addon-options": "5.3.1",
80-
"@storybook/react": "5.3.1",
78+
"@storybook/addon-actions": "5.3.5",
79+
"@storybook/addon-knobs": "5.3.5",
80+
"@storybook/addon-notes": "5.3.5",
81+
"@storybook/addon-options": "5.3.5",
82+
"@storybook/react": "5.3.5",
8183
"@testing-library/react-hooks": "3.2.1",
82-
"@types/jest": "24.0.25",
84+
"@types/jest": "24.9.0",
8385
"@types/react": "16.9.11",
8486
"babel-core": "6.26.3",
8587
"babel-loader": "8.0.6",
@@ -88,6 +90,7 @@
8890
"gh-pages": "2.2.0",
8991
"husky": "3.1.0",
9092
"jest": "24.9.0",
93+
"jest-localstorage-mock": "2.4.0",
9194
"keyboardjs": "2.5.1",
9295
"lint-staged": "9.5.0",
9396
"markdown-loader": "5.1.0",
@@ -106,13 +109,13 @@
106109
"semantic-release": "15.14.0",
107110
"ts-jest": "24.3.0",
108111
"ts-loader": "6.2.1",
109-
"ts-node": "8.6.1",
112+
"ts-node": "8.6.2",
110113
"tslint": "6.0.0-beta1",
111114
"tslint-config-prettier": "1.18.0",
112115
"tslint-eslint-rules": "5.4.0",
113116
"tslint-plugin-prettier": "2.1.0",
114117
"tslint-react": "4.1.0",
115-
"typescript": "3.7.4"
118+
"typescript": "3.7.5"
116119
},
117120
"config": {
118121
"commitizen": {
@@ -160,7 +163,8 @@
160163
"<rootDir>/tests/**/*.test.(ts|tsx)"
161164
],
162165
"setupFiles": [
163-
"<rootDir>/tests/_setup.js"
166+
"<rootDir>/tests/_setup.js",
167+
"./tests/setupTests.ts"
164168
]
165169
}
166170
}

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export { default as useBattery } from './useBattery';
88
export { default as useBeforeUnload } from './useBeforeUnload';
99
export { default as useBoolean } from './useBoolean';
1010
export { default as useClickAway } from './useClickAway';
11+
export { default as useCookie } from './useCookie';
1112
export { default as useCopyToClipboard } from './useCopyToClipboard';
1213
export { default as useCounter } from './useCounter';
1314
export { default as useCss } from './useCss';
@@ -20,6 +21,7 @@ export { default as useDropArea } from './useDropArea';
2021
export { default as useEffectOnce } from './useEffectOnce';
2122
export { default as useEnsuredForwardedRef, ensuredForwardRef } from './useEnsuredForwardedRef';
2223
export { default as useEvent } from './useEvent';
24+
export { default as useError } from './useError';
2325
export { default as useFavicon } from './useFavicon';
2426
export { default as useFullscreen } from './useFullscreen';
2527
export { default as useGeolocation } from './useGeolocation';

src/useCookie.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { useState, useCallback } from 'react';
2+
import Cookies from 'js-cookie';
3+
4+
const useCookie = (
5+
cookieName: string
6+
): [string | null, (newValue: string, options?: Cookies.CookieAttributes) => void, () => void] => {
7+
const [value, setValue] = useState<string | null>(() => Cookies.get(cookieName) || null);
8+
9+
const updateCookie = useCallback(
10+
(newValue: string, options?: Cookies.CookieAttributes) => {
11+
Cookies.set(cookieName, newValue, options);
12+
setValue(newValue);
13+
},
14+
[cookieName]
15+
);
16+
17+
const deleteCookie = useCallback(() => {
18+
Cookies.remove(cookieName);
19+
setValue(null);
20+
}, [cookieName]);
21+
22+
return [value, updateCookie, deleteCookie];
23+
};
24+
25+
export default useCookie;

src/useError.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { useState, useEffect, useCallback } from 'react';
2+
3+
const useError = (): ((err: Error) => void) => {
4+
const [error, setError] = useState<Error | null>(null);
5+
6+
useEffect(() => {
7+
if (error) {
8+
throw error;
9+
}
10+
}, [error]);
11+
12+
const dispatchError = useCallback((err: Error) => {
13+
setError(err);
14+
}, []);
15+
16+
return dispatchError;
17+
};
18+
19+
export default useError;

src/useLocalStorage.ts

+20-12
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,41 @@
11
import { useEffect, useState, useCallback } from 'react';
22
import { isClient } from './util';
33

4-
type Dispatch<A> = (value: A) => void;
5-
type SetStateAction<S> = S | ((prevState: S) => S);
4+
type parserOptions<T> =
5+
| {
6+
raw: true;
7+
}
8+
| {
9+
raw: false;
10+
serializer: (value: T) => string;
11+
deserializer: (value: string) => T;
12+
};
613

714
const noop = () => {};
815
const isUndefined = (value?: any): boolean => typeof value === 'undefined';
916

1017
const useLocalStorage = <T>(
1118
key: string,
1219
initialValue?: T,
13-
raw?: boolean
14-
): [T | undefined, Dispatch<SetStateAction<T | undefined>>, () => void] => {
20+
options?: parserOptions<T>
21+
): [T | undefined, React.Dispatch<React.SetStateAction<T | undefined>>, () => void] => {
1522
if (!isClient) {
1623
return [initialValue as T, noop, noop];
1724
}
1825

26+
// Use provided serializer/deserializer or the default ones
27+
const serializer = options ? (options.raw ? String : options.serializer) : JSON.stringify;
28+
const deserializer = options ? (options.raw ? String : options.deserializer) : JSON.parse;
29+
1930
const [state, setState] = useState<T | undefined>(() => {
2031
try {
2132
const localStorageValue = localStorage.getItem(key);
22-
if (isUndefined(initialValue)) {
23-
return undefined;
24-
}
25-
if (typeof localStorageValue !== 'string') {
26-
localStorage.setItem(key, raw ? String(initialValue) : JSON.stringify(initialValue));
33+
if (localStorageValue !== null) {
34+
return deserializer(localStorageValue);
35+
} else {
36+
initialValue && localStorage.setItem(key, serializer(initialValue));
2737
return initialValue;
2838
}
29-
return raw ? localStorageValue : JSON.parse(localStorageValue || 'null');
3039
} catch {
3140
// If user is in private mode or has storage restriction
3241
// localStorage can throw. JSON.parse and JSON.stringify
@@ -48,8 +57,7 @@ const useLocalStorage = <T>(
4857
useEffect(() => {
4958
if (isUndefined(state)) return;
5059
try {
51-
const serializedState = raw ? String(state) : JSON.stringify(state);
52-
localStorage.setItem(key, serializedState);
60+
localStorage.setItem(key, serializer(state));
5361
} catch {
5462
// If user is in private mode or has storage restriction
5563
// localStorage can throw. Also JSON.stringify can throw.

0 commit comments

Comments
 (0)