From 169676bfbd5f7143634d5d3ddb3e48314e235a47 Mon Sep 17 00:00:00 2001 From: Ashish-simpleCoder Date: Wed, 15 Oct 2025 22:24:54 +0530 Subject: [PATCH 1/2] fix: missing export for use-multi-intersection-observer hook --- .changeset/spotty-jeans-carry.md | 5 +++++ src/index.tsx | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/spotty-jeans-carry.md diff --git a/.changeset/spotty-jeans-carry.md b/.changeset/spotty-jeans-carry.md new file mode 100644 index 0000000..6c70060 --- /dev/null +++ b/.changeset/spotty-jeans-carry.md @@ -0,0 +1,5 @@ +--- +'classic-react-hooks': minor +--- + +- Fix missing import for `useMultipleIntersectionObserver` hook diff --git a/src/index.tsx b/src/index.tsx index f54fc8d..07e3857 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -26,3 +26,4 @@ export { default as useOnMountEffect } from './lib/use-on-mount-effect' export { default as useCounter } from './lib/use-counter' export { default as useInterSectionObserver } from './lib/use-intersection-observer' +export { default as useMultipleIntersectionObserver } from './lib/use-multi-intersection-observer' From 0d6f6d2b4e8cfcd6c3ce1231e35c6fa44efa192c Mon Sep 17 00:00:00 2001 From: Ashish-simpleCoder Date: Wed, 15 Oct 2025 22:25:19 +0530 Subject: [PATCH 2/2] fix: missing export for use-multi-intersection-observer hook --- .changeset/spotty-jeans-carry.md | 2 +- use-local.tsx | 108 +++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 use-local.tsx diff --git a/.changeset/spotty-jeans-carry.md b/.changeset/spotty-jeans-carry.md index 6c70060..7ed304b 100644 --- a/.changeset/spotty-jeans-carry.md +++ b/.changeset/spotty-jeans-carry.md @@ -2,4 +2,4 @@ 'classic-react-hooks': minor --- -- Fix missing import for `useMultipleIntersectionObserver` hook +- Fix missing export for `useMultipleIntersectionObserver` hook diff --git a/use-local.tsx b/use-local.tsx new file mode 100644 index 0000000..d8805e1 --- /dev/null +++ b/use-local.tsx @@ -0,0 +1,108 @@ +import { useCallback, useRef, useSyncExternalStore } from 'react' + +export default function useLocal({ key, initialValue }: { key: string, initialValue?: State | (() => State) }) { + // Cache the last parse value to avoid unnecessary re-renders + const lastValueRef = useRef(null) + const lastStringRef = useRef(null) + const lastKeyRef = useRef(key) + + const getStoredState = useCallback(() => { + try { + // Key has changed, reset cached values + if (lastKeyRef.current !== key) { + localStorage.removeItem(lastKeyRef.current) + lastKeyRef.current = key + lastValueRef.current = null + lastStringRef.current = null + } + + const item = localStorage.getItem(key) + + if (item != null) { + // Only parse if the string value has changed + if (lastStringRef.current !== item) { + lastStringRef.current = item + lastValueRef.current = JSON.parse(item) + } + return lastValueRef.current! + } + } catch (err) { + console.log(err) + } + + // Return initial value + let returnVal: State + if (typeof initialValue == "function") { + returnVal = (initialValue as () => State)() + } else { + returnVal = initialValue as State + } + + // Cache the initial value + lastValueRef.current = returnVal + return returnVal + }, [key, initialValue]) + + // Server-side snapshot - return initial value to avoid hydration mismatch + const getServerSnapshot = useCallback(() => { + if (typeof initialValue == 'function') { + return (initialValue as () => State)() + } + return initialValue as State + }, [initialValue]) + + const storedState = useSyncExternalStore( + useCallback((callback) => { + const handleStorageChange = (event: Event) => { + callback() + } + + // Listen for our custom events + window.addEventListener(key, handleStorageChange) + + // Also listen for storage event from other tabs + const handleStorageEvent = (event: StorageEvent) => { + if (event.key === key) { + callback() + } + } + + window.addEventListener('storage', handleStorageEvent) + + return () => { + window.removeEventListener(key, handleStorageChange) + window.removeEventListener('storage', handleStorageEvent) + } + }, []), + getStoredState, + getServerSnapshot + ) + + const updateState = useCallback(() => { + (value: State | (() => State)) => { + try { + let newValue: State + + if (typeof value === 'function') { + newValue = (value as (state: State) => State)(storedState) + } else { + newValue = value + } + + const serializedValue = JSON.stringify(newValue) + localStorage.setItem(key, serializedValue) + + // Update cache + lastStringRef.current = serializedValue + lastValueRef.current = newValue + + // Notify subscriber + window.dispatchEvent(new Event(key)) + } catch (err) { + console.log(err) + } + } + }, [key, storedState]) + + return [storedState, updateState] as const +} \ No newline at end of file