Releases: childrentime/reactuse
Release list
v6.5.0
📦 Build
Per-module dist: optimizePackageImports now works — #216
The published dist previously inlined all 120+ hooks into a single bundle, so barrel-file optimizers had nothing to unroll: a Next.js (Turbopack) dev page importing just useDebounce pulled in every hook — a 552 kB client chunk. The build now ships one file per module (tsdown with unbundle, i.e. preserveModules) with the entry as a thin barrel of re-exports, and the same page loads only useDebounce and its real dependency chain: 64 kB (−88%).
With this release, Next.js users can enable:
// next.config.js
module.exports = {
experimental: {
optimizePackageImports: ['@reactuses/core']
}
}✨ Direct subpath imports
Every hook is now importable directly, skipping the barrel entirely — no bundler configuration needed:
import { useDebounce } from '@reactuses/core/useDebounce'Notes
requireentries now resolve to./dist/index.js/./dist/index.d.ts(previously.cjs/.d.cts);./useQRCodemoved to./dist/useQRCode/index.*. Both were only reachable through theexportsmap, so consumers are unaffected.- Build tool switched from bunchee to tsdown; bunchee dropped from the root workspace.
Full PR: #216
v6.4.2
🐛 Fixes
useOrientation: lockOrientation / unlockOrientation were no-ops — closes #215
Both methods guarded with if (isBrowser) return — inverted. They returned early in the browser and only proceeded during SSR, where the follow-up 'screen' in window check bailed anyway. The result: calling lockOrientation('landscape') or unlockOrientation() silently did nothing, everywhere. The guards now read if (!isBrowser) return, and the PR adds browser + SSR specs so the direction can't flip again unnoticed.
Full PR: #215
useInterval: a manually resumed interval survived unmount — closes #212
Two leaks in controls mode:
- With
controls: truethe main effect returns before registering a cleanup, so an interval started throughresume()kept firing after the component unmounted — despite the docs promising it's cleared on unmount. The cleanup now runs in its own mount-scoped effect, covering both modes without changing thedelay-update behavior. resume()overwrotetimer.currentwithout clearing the previous timer, so calling it twice left an interval that neitherpause()nor the unmount cleanup could reach. It now clears any running timer before starting a new one.
Full PR: #212
useMicrophone: level stayed frozen after stop() — closes #213
teardownAudioGraph() cancels the rAF loop, which is the only writer of level, so after stop() the value froze at whatever the last frame measured. A volume meter bound to it kept showing input long after the microphone was released. stop() now resets level to 0.
Full PR: #213
useElementByPoint: no more re-render on every frame in multiple mode — closes #214
document.elementsFromPoint() allocates a fresh array on every call, so storing its result as-is re-rendered the component on every frame of the rAF loop — even with the pointer sitting still. The hit list is now compared element-by-element inside a functional update, and the previous state is kept when nothing changed. The single-element mode needed no change: elementFromPoint() returns the same node and React bails out on its own.
Full PR: #214
Thanks @ostapondo for all four reports and fixes.
🔧 Internal
- CI now runs a dedicated typecheck gate (
tsc --noEmit), and TypeScript versions are aligned across the workspace (#211). As part of it,useGeolocation's placeholder coords gained thetoJSONthatGeolocationCoordinatescarries in lib.dom.
v6.4.1
🐛 Fixes
useScriptTag no longer emits an unhandled promise rejection — closes #206
The immediate auto-load called load() as a bare statement, so nothing was attached to the promise it returns. When the script failed — blocked by an ad blocker, offline, 404 — the error listener rejected that promise with no handler, and the rejection reached window.onunhandledrejection, where error trackers reported it. Setting status to 'error' does not mark a promise handled; setStatus and reject are independent paths.
Any useScriptTag pointing at analytics, a chat widget, or a third-party SDK hit this for every user running a blocklist.
The auto-load now attaches a no-op catch:
status === 'error'remains the reporting channel for a load nobody awaited.- Callers that hold the promise themselves are unaffected —
load()memoizes into_promise.current, so an explicitload()returns the same promise and still rejects for them.
Thanks @Faithfinder for the report and the fix.
Full PR: #206
v6.4.0
✨ Features
Same-tab component sync for storage & cookie hooks — closes #202
Two components bound to the same key in the same tab now stay in sync. The native storage event only fires in other tabs, so previously a header and footer useColorMode (or two useCookie on the same key) never updated each other.
useLocalStorage/useSessionStorage(createStorage): each write re-broadcasts a customwindowevent that sibling instances pick up viauseEventListener; cross-tab sync still rides the nativestorageevent.useCookie: same primitive — cookies fire no native event.refreshCookiestays for changes made outside the hook.useColorMode/useDarkMode: inherit it for free (built oncreateStorage).
Notes:
- Uses a
windowevent (not a module-level registry) so it survives the library being bundled more than once. listenToStorageChangesnow gates the cross-tab listener only; same-tab sync is always on.
🐛 Fixes
useTimeout/useTimeoutFnno longer flashpendingfalse → trueon mount — it seeds the real armed value fromimmediate. Closes #203.
📖 Docs
Corrected the useCookie / useLocalStorage / useSessionStorage sync notes and added clickable two-component live demos (en + zh-Hans + zh-Hant).
Full PR: #204
v6.3.2
Bug Fixes
- core: emit default values in the generated API docs. Five hooks used the non-standard
@defaultJSDoc tag, which the doc generator silently dropped (rendering the default column as-). Switched to the TSDoc-standard@defaultValuetag so defaults now show correctly.- Affected hooks:
useMicrophone,useElementBounding,useScroll,useScratch,useSpeechRecognition(anduseInfiniteScroll, which reuses theuseScrolloptions).
- Affected hooks:
Docs
- Add the
useWakeLockAPI reference, which was never generated/committed when the hook landed (#194), so its docs page no longer renders an empty API table.
Note: runtime bundle is unchanged from v6.3.1 — this release only corrects JSDoc/type metadata (.d.ts) and the generated documentation tables.
v6.3.1
Bug Fixes
- useClipboard: fix SSR safety issue — replace direct
windowreference withdefaultWindowin focus event listener to preventReferenceErrorin server-side rendering environments
v6.3.0
What's Changed
Refactor
- createStorage: Replace
useState+useDeepCompareEffectwithuseSyncExternalStore, eliminating CSR first-render flicker, SSR hydration mismatches, and stale cross-tab reads (#195)
Bug Fixes
- createStorage: Fix stale closure in consecutive functional updates within the same synchronous batch —
updateStatenow reads fromgetSnapshot()instead of the render-timestate
Tests
- useLocalStorage: Add 12 new test cases covering cross-tab sync,
storage.clear(),listenToStorageChangestoggle, three-state semantics,onError,mountStorageValue, and consecutive functional updates
Full Changelog: v6.1.12...v6.3.0
v6.1.12
- fix(useGeolocation): make useSupported check more robust
6.1.2(Oct 30, 2025)
- feat: add useScratch hook.
6.1.0(Sep 24, 2025)
Breaking Changes
- useDarkMode: Storage format changed from boolean to string values ('dark'/'light'). This affects localStorage/sessionStorage data and SSR scripts. Existing stored boolean values will be automatically migrated, but custom SSR scripts need to be updated to handle string comparisons instead of boolean values.
Core
- feat: add useMap hook for reactive Map state management with set, get, remove, has, clear, and reset operations
- feat: add useColorMode hook with support for multiple color modes beyond dark/light
- feat: add useBoolean hook for boolean state management with setValue, setTrue, setFalse, and toggle operations
- feat: add useClickAway alias for useClickOutside hook
- feat: add useCopyToClipboard alias for useClipboard hook
- feat: add comprehensive documentation for useColorMode hook
- docs: add context provider examples for both useColorMode and useDarkMode
- docs: add multi-color theme examples in useColorMode documentation (6 themes: light, dark, blue, green, purple, sepia)
- docs: update useDarkMode documentation scripts to handle new string storage format