Skip to content

Commit

Permalink
feat: add useCookie hook
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jan 13, 2020
2 parents 0d2c7b6 + 3e806fd commit 4e5c90f
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 0 deletions.
39 changes: 39 additions & 0 deletions docs/useCookie.md
@@ -0,0 +1,39 @@
# `useCookie`

React hook that returns the current value of a `cookie`, a callback to update the `cookie`
and a callback to delete the `cookie.`

## Usage

```jsx
import { useCookie } from "react-use";

const Demo = () => {
const [value, updateCookie, deleteCookie] = useCookie("my-cookie");
const [counter, setCounter] = useState(1);

useEffect(() => {
deleteCookie();
}, []);

const updateCookieHandler = () => {
updateCookie(`my-awesome-cookie-${counter}`);
setCounter(c => c + 1);
};

return (
<div>
<p>Value: {value}</p>
<button onClick={updateCookieHandler}>Update Cookie</button>
<br />
<button onClick={deleteCookie}>Delete Cookie</button>
</div>
);
};
```

## Reference

```ts
const [value, updateCookie, deleteCookie] = useCookie(cookieName: string);
```
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -49,6 +49,7 @@
"@xobotyi/scrollbar-width": "1.5.0",
"copy-to-clipboard": "^3.2.0",
"fast-shallow-equal": "^1.0.0",
"js-cookie": "^2.2.1",
"nano-css": "^5.2.1",
"react-fast-compare": "^2.0.4",
"resize-observer-polyfill": "^1.5.1",
Expand Down Expand Up @@ -79,6 +80,7 @@
"@storybook/react": "5.3.1",
"@testing-library/react-hooks": "3.2.1",
"@types/jest": "24.0.25",
"@types/js-cookie": "^2.2.4",
"@types/react": "16.9.11",
"babel-core": "6.26.3",
"babel-loader": "8.0.6",
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Expand Up @@ -8,6 +8,7 @@ export { default as useBattery } from './useBattery';
export { default as useBeforeUnload } from './useBeforeUnload';
export { default as useBoolean } from './useBoolean';
export { default as useClickAway } from './useClickAway';
export { default as useCookie } from './useCookie';
export { default as useCopyToClipboard } from './useCopyToClipboard';
export { default as useCounter } from './useCounter';
export { default as useCss } from './useCss';
Expand Down
25 changes: 25 additions & 0 deletions src/useCookie.ts
@@ -0,0 +1,25 @@
import { useState, useCallback } from 'react';
import Cookies from 'js-cookie';

const useCookie = (
cookieName: string
): [string | null, (newValue: string, options?: Cookies.CookieAttributes) => void, () => void] => {
const [value, setValue] = useState<string | null>(() => Cookies.get(cookieName) || null);

const updateCookie = useCallback(
(newValue: string, options?: Cookies.CookieAttributes) => {
Cookies.set(cookieName, newValue, options);
setValue(newValue);
},
[cookieName]
);

const deleteCookie = useCallback(() => {
Cookies.remove(cookieName);
setValue(null);
}, [cookieName]);

return [value, updateCookie, deleteCookie];
};

export default useCookie;
31 changes: 31 additions & 0 deletions stories/useCookie.story.tsx
@@ -0,0 +1,31 @@
import { storiesOf } from "@storybook/react";
import React, { useState, useEffect } from "react";
import { useCookie } from "../src";
import ShowDocs from "./util/ShowDocs";

const Demo = () => {
const [value, updateCookie, deleteCookie] = useCookie("my-cookie");
const [counter, setCounter] = useState(1);

useEffect(() => {
deleteCookie();
}, []);

const updateCookieHandler = () => {
updateCookie(`my-awesome-cookie-${counter}`);
setCounter(c => c + 1);
};

return (
<div>
<p>Value: {value}</p>
<button onClick={updateCookieHandler}>Update Cookie</button>
<br />
<button onClick={deleteCookie}>Delete Cookie</button>
</div>
);
};

storiesOf("Side effects|useCookie", module)
.add("Docs", () => <ShowDocs md={require("../docs/useCookie.md")} />)
.add("Demo", () => <Demo />);
68 changes: 68 additions & 0 deletions tests/useCookie.test.tsx
@@ -0,0 +1,68 @@
import { renderHook, act } from '@testing-library/react-hooks';
import Cookies from 'js-cookie';
import { useCookie } from '../src';

const setup = (cookieName: string) => renderHook(() => useCookie(cookieName));

it('should have initial value of null if no cookie exists', () => {
const { result } = setup('some-cookie');

expect(result.current[0]).toBeNull();
});

it('should have initial value of the cookie if it exists', () => {
const cookieName = 'some-cookie';
const value = 'some-value';
Cookies.set(cookieName, value);

const { result } = setup(cookieName);

expect(result.current[0]).toBe(value);

// cleanup
Cookies.remove(cookieName);
});

it('should update the cookie on call to updateCookie', () => {
const spy = jest.spyOn(Cookies, 'set');

const cookieName = 'some-cookie';
const { result } = setup(cookieName);

const newValue = 'some-new-value';
act(() => {
result.current[1](newValue);
});

expect(result.current[0]).toBe(newValue);
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenCalledWith(cookieName, newValue, undefined);

// cleanup
spy.mockRestore();
Cookies.remove(cookieName);
});

it('should delete the cookie on call to deleteCookie', () => {
const cookieName = 'some-cookie';
const value = 'some-value';
Cookies.set(cookieName, value);

const spy = jest.spyOn(Cookies, 'remove');

const { result } = setup(cookieName);

expect(result.current[0]).toBe(value);

act(() => {
result.current[2]();
});

expect(result.current[0]).toBeNull();
expect(spy).toHaveBeenCalledTimes(1);
expect(spy).toHaveBeenLastCalledWith(cookieName);

// cleanup
spy.mockRestore();
Cookies.remove(cookieName);
});
10 changes: 10 additions & 0 deletions yarn.lock
Expand Up @@ -2929,6 +2929,11 @@
dependencies:
jest-diff "^24.3.0"

"@types/js-cookie@^2.2.4":
version "2.2.4"
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.4.tgz#f79720b4755aa197c2e15e982e2f438f5748e348"
integrity sha512-WTfSE1Eauak/Nrg6cA9FgPTFvVawejsai6zXoq0QYTQ3mxONeRtGhKxa7wMlUzWWmzrmTeV+rwLjHgsCntdrsA==

"@types/lolex@^2.1.3":
version "2.1.3"
resolved "https://registry.yarnpkg.com/@types/lolex/-/lolex-2.1.3.tgz#793557c9b8ad319b4c8e4c6548b90893f4aa5f69"
Expand Down Expand Up @@ -8787,6 +8792,11 @@ jest@24.9.0:
import-local "^2.0.0"
jest-cli "^24.9.0"

js-cookie@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==

js-levenshtein@^1.1.3:
version "1.1.6"
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
Expand Down

0 comments on commit 4e5c90f

Please sign in to comment.