From f339a7c81abf9f05fd340385431b4f57cb3c8854 Mon Sep 17 00:00:00 2001 From: Daniel Schmidt Date: Wed, 4 Dec 2024 16:37:27 +0100 Subject: [PATCH] feat: add revalidateCookies --- README.md | 8 ++++++++ src/__tests__/useCookie.test.ts | 30 +++++++++++++++++++++++++----- src/hooks/useCookie.ts | 7 +++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a2dc22c..976cd3b 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,14 @@ import { useCookie } from "@charlietango/hooks/use-cookie"; const [value, setValue] = useCookie("mode"); ``` +If the cookies is changed outside the `useCookie` hook, you can call the `revalidateCookies`, to get React to reevaluate the cookie values. + +```ts +import { revalidateCookies } from "@charlietango/hooks/use-cookie"; + +revalidateCookies(); +``` + ### `useDebouncedValue` Debounce a value. The value will only be updated after the delay has passed without the value changing. diff --git a/src/__tests__/useCookie.test.ts b/src/__tests__/useCookie.test.ts index f34f0eb..45e79eb 100644 --- a/src/__tests__/useCookie.test.ts +++ b/src/__tests__/useCookie.test.ts @@ -1,5 +1,5 @@ import { act, renderHook } from "@testing-library/react"; -import { useCookie } from "../hooks/useCookie"; +import { revalidateCookies, useCookie } from "../hooks/useCookie"; function setValue( value: string | ((prevValue?: string) => string | undefined) | undefined, @@ -14,8 +14,15 @@ function getValue(hook: { current: ReturnType }) { return hook.current[0]; } +afterEach(() => { + // Clear all cookies after each test + document.cookie.split(";").forEach((c) => { + document.cookie = `${c.trim().split("=")[0]}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;`; + }); +}); + test("should manage cookies", () => { - const { result: hook } = renderHook(() => useCookie("test")); + const { result: hook } = renderHook(() => useCookie("manage-test")); setValue("custom value", hook); @@ -30,7 +37,7 @@ test("should manage cookies", () => { test("should manage cookies with default value", () => { const { result: hook } = renderHook(() => - useCookie("test", { defaultValue: "default value" }), + useCookie("default-value", { defaultValue: "default value" }), ); expect(getValue(hook)).toBe("default value"); @@ -43,11 +50,24 @@ test("should manage cookies with default value", () => { }); test("should sync values across hooks", () => { - const { result: hook } = renderHook(() => useCookie("test")); - const { result: hook2 } = renderHook(() => useCookie("test")); + const { result: hook } = renderHook(() => useCookie("sync")); + const { result: hook2 } = renderHook(() => useCookie("sync")); setValue("new value", hook); expect(getValue(hook)).toBe("new value"); expect(getValue(hook2)).toBe("new value"); }); + +test("should be able to revalidate cookies externally", () => { + const { result: hook } = renderHook(() => useCookie("external")); + document.cookie = "external=new value"; + expect(hook.current[0]).toBe(undefined); + + act(() => { + // Revalidate the cookies, trigger the external sync + revalidateCookies(); + }); + + expect(hook.current[0]).toBe("new value"); +}); diff --git a/src/hooks/useCookie.ts b/src/hooks/useCookie.ts index 7229cbd..36d3333 100644 --- a/src/hooks/useCookie.ts +++ b/src/hooks/useCookie.ts @@ -13,6 +13,13 @@ type Options = { cookieOptions?: CookieOptions; }; +/** + * Revalidate the cookies. Useful to update the cookies when they are changed outside the hook, e.g. by a server response. + */ +export function revalidateCookies() { + trigger(SUBSCRIPTION_KEY); +} + /** * Get or set a cookie, and update the value when it changes * @param key {string} The name of the cookie.