From bc72bc13e7020b94ec6e542d94afeb2bcf6000ab Mon Sep 17 00:00:00 2001 From: Ayush Goyal Date: Sun, 12 Jan 2020 02:00:24 +0530 Subject: [PATCH 1/3] Add useCookie hook --- docs/useCookie.md | 39 +++++++++++++++++++++ package.json | 2 ++ src/index.ts | 1 + src/useCookie.ts | 25 ++++++++++++++ stories/useCookie.story.tsx | 31 +++++++++++++++++ tests/useCookie.test.tsx | 68 +++++++++++++++++++++++++++++++++++++ yarn.lock | 10 ++++++ 7 files changed, 176 insertions(+) create mode 100644 docs/useCookie.md create mode 100644 src/useCookie.ts create mode 100644 stories/useCookie.story.tsx create mode 100644 tests/useCookie.test.tsx diff --git a/docs/useCookie.md b/docs/useCookie.md new file mode 100644 index 0000000000..24e786ca4c --- /dev/null +++ b/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 ( +
+

Value: {value}

+ +
+ +
+ ); +}; +``` + +## Reference + +```ts +useCookie(cookieName: string); +``` diff --git a/package.json b/package.json index 03f3403fd0..208aa5514a 100644 --- a/package.json +++ b/package.json @@ -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", @@ -79,6 +80,7 @@ "@storybook/react": "5.3.0", "@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", diff --git a/src/index.ts b/src/index.ts index 4a0aee4fa7..dc6f65ff8c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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'; diff --git a/src/useCookie.ts b/src/useCookie.ts new file mode 100644 index 0000000000..d81500887c --- /dev/null +++ b/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(() => 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; diff --git a/stories/useCookie.story.tsx b/stories/useCookie.story.tsx new file mode 100644 index 0000000000..89d3f753db --- /dev/null +++ b/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 ( +
+

Value: {value}

+ +
+ +
+ ); +}; + +storiesOf("Side effects|useCookie", module) + .add("Docs", () => ) + .add("Demo", () => ); diff --git a/tests/useCookie.test.tsx b/tests/useCookie.test.tsx new file mode 100644 index 0000000000..6a3a12a0f1 --- /dev/null +++ b/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); +}); diff --git a/yarn.lock b/yarn.lock index 0ea63bc083..5ca3d5e301 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2712,6 +2712,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" @@ -8565,6 +8570,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" From c3c9061dbc23b82ac4d2d500757862112456481b Mon Sep 17 00:00:00 2001 From: Ayush Goyal Date: Sun, 12 Jan 2020 02:06:05 +0530 Subject: [PATCH 2/3] update for prettier changes --- tests/useCookie.test.tsx | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/useCookie.test.tsx b/tests/useCookie.test.tsx index 6a3a12a0f1..cc72dc460a 100644 --- a/tests/useCookie.test.tsx +++ b/tests/useCookie.test.tsx @@ -1,18 +1,18 @@ -import { renderHook, act } from "@testing-library/react-hooks"; -import Cookies from "js-cookie"; -import { useCookie } from "../src"; +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"); +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"; +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); @@ -23,13 +23,13 @@ it("should have initial value of the cookie if it exists", () => { Cookies.remove(cookieName); }); -it("should update the cookie on call to updateCookie", () => { - const spy = jest.spyOn(Cookies, "set"); +it('should update the cookie on call to updateCookie', () => { + const spy = jest.spyOn(Cookies, 'set'); - const cookieName = "some-cookie"; + const cookieName = 'some-cookie'; const { result } = setup(cookieName); - const newValue = "some-new-value"; + const newValue = 'some-new-value'; act(() => { result.current[1](newValue); }); @@ -43,12 +43,12 @@ it("should update the cookie on call to updateCookie", () => { Cookies.remove(cookieName); }); -it("should delete the cookie on call to deleteCookie", () => { - const cookieName = "some-cookie"; - const value = "some-value"; +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 spy = jest.spyOn(Cookies, 'remove'); const { result } = setup(cookieName); From 3e806fdc03c9f25e11490d1ccc4bda42fd9f37f9 Mon Sep 17 00:00:00 2001 From: Ayush Goyal Date: Mon, 13 Jan 2020 07:26:33 +0530 Subject: [PATCH 3/3] Update ts ref in doc --- docs/useCookie.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/useCookie.md b/docs/useCookie.md index 24e786ca4c..92bf9f63e7 100644 --- a/docs/useCookie.md +++ b/docs/useCookie.md @@ -35,5 +35,5 @@ const Demo = () => { ## Reference ```ts -useCookie(cookieName: string); +const [value, updateCookie, deleteCookie] = useCookie(cookieName: string); ```