From 963879e3b093dd10bf027e72f8d5ee4b3c0a6b12 Mon Sep 17 00:00:00 2001 From: Ian K Smith Date: Thu, 6 Oct 2022 11:06:41 -0600 Subject: [PATCH 1/2] New hooks: useCallbackConst, useCallbackRef, useValueRef --- README.md | 3 +++ docs/use-callback-const.md | 3 +++ docs/use-callback-ref.md | 3 +++ docs/use-value-ref.md | 3 +++ src/hooks/use-callback-const/index.ts | 8 ++++++++ src/hooks/use-callback-ref/index.ts | 13 +++++++++++++ src/hooks/use-const/index.ts | 14 +++++--------- src/hooks/use-value-ref/index.ts | 17 +++++++++++++++++ src/index.ts | 3 +++ 9 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 docs/use-callback-const.md create mode 100644 docs/use-callback-ref.md create mode 100644 docs/use-value-ref.md create mode 100644 src/hooks/use-callback-const/index.ts create mode 100644 src/hooks/use-callback-ref/index.ts create mode 100644 src/hooks/use-value-ref/index.ts diff --git a/README.md b/README.md index 0c2228c..fcfade9 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ npm install usable-react ## Documentation - [`useAsyncEffect`](./docs/use-async-effect.md) +- [`useCallbackConst`](./docs/use-callback-const.md) +- [`useCallbackRef`](./docs/use-callback-ref.md) - [`useClickOutside`](./docs/use-click-outside.md) - [`useClipboard`](./docs/use-clipboard.md) - [`useCompare`](./docs/use-compare.md) @@ -46,4 +48,5 @@ npm install usable-react - [`usePrevious`](./docs/use-previous.md) - [`useResizeObserver`](./docs/use-resize-observer.md) - [`useTimer`](./docs/use-timer.md) +- [`useValueRef`](./docs/use-value-ref.md) diff --git a/docs/use-callback-const.md b/docs/use-callback-const.md new file mode 100644 index 0000000..1d12202 --- /dev/null +++ b/docs/use-callback-const.md @@ -0,0 +1,3 @@ +# `useCallbackConst` + +Documentation coming soon... diff --git a/docs/use-callback-ref.md b/docs/use-callback-ref.md new file mode 100644 index 0000000..b6bc1d1 --- /dev/null +++ b/docs/use-callback-ref.md @@ -0,0 +1,3 @@ +# `useCallbackRef` + +Documentation coming soon... diff --git a/docs/use-value-ref.md b/docs/use-value-ref.md new file mode 100644 index 0000000..0c7c944 --- /dev/null +++ b/docs/use-value-ref.md @@ -0,0 +1,3 @@ +# `useValueRef` + +Documentation coming soon... diff --git a/src/hooks/use-callback-const/index.ts b/src/hooks/use-callback-const/index.ts new file mode 100644 index 0000000..f8070f5 --- /dev/null +++ b/src/hooks/use-callback-const/index.ts @@ -0,0 +1,8 @@ +import { useConst } from '../use-const'; + +/** + * Creates a callback with a constant value over the lifecycle of a component. + */ +export function useCallbackConst any>(callback: T): T { + return useConst(() => callback); +} diff --git a/src/hooks/use-callback-ref/index.ts b/src/hooks/use-callback-ref/index.ts new file mode 100644 index 0000000..c828979 --- /dev/null +++ b/src/hooks/use-callback-ref/index.ts @@ -0,0 +1,13 @@ +import { useCallbackConst } from '../use-callback-const'; +import { useValueRef } from '../use-value-ref'; + +/** + * Converts a callback to a ref to avoid triggering re-renders when passed as a + * prop or avoid re-executing effects when passed as a dependency. + * + * Returns a new callback with a constant value over the lifecycle of a component. + */ +export function useCallbackRef any>(callback?: T): T { + const callbackRef = useValueRef(callback); + return useCallbackConst(((...args) => callbackRef.current?.(...args)) as T); +} diff --git a/src/hooks/use-const/index.ts b/src/hooks/use-const/index.ts index fafeaef..77730c7 100644 --- a/src/hooks/use-const/index.ts +++ b/src/hooks/use-const/index.ts @@ -8,9 +8,12 @@ import { useRef } from 'react'; * @see the LICENSE file at the root of this source tree: * https://github.com/chakra-ui/chakra-ui/blob/6e259a1f7008a00f7be096e6b315cb9d62ef9748/packages/hooks/src/use-const.ts * - * Modifications from original source: none + * Modifications from original source: + * - TypeScript improvements using overload definitions */ -export function useConst(init: T | (() => T)): T { +export function useConst(init: T | (() => T)): T; +export function useConst(): T | undefined; +export function useConst(init?: T | (() => T)): T | undefined { // `useRef` is less expensive than `useState`. const ref = useRef(null); @@ -20,10 +23,3 @@ export function useConst(init: T | (() => T)): T { return ref.current as T; } - -/** - * Creates a callback with a constant value over the lifecycle of a component. - */ -export function useCallbackConst any>(callback: T): T { - return useConst(() => callback); -} diff --git a/src/hooks/use-value-ref/index.ts b/src/hooks/use-value-ref/index.ts new file mode 100644 index 0000000..389f928 --- /dev/null +++ b/src/hooks/use-value-ref/index.ts @@ -0,0 +1,17 @@ +import { useEffect, useRef } from 'react'; + +/** + * Converts `value` to a ref to avoid triggering re-renders when passed as a + * prop or avoid re-executing effects when passed as a dependency. + * + * Returns a ref object with a constant value over the lifecycle of a component. + */ +export function useValueRef(value: T) { + const valueRef = useRef(value); + + useEffect(() => { + valueRef.current = value; + }); + + return valueRef; +} diff --git a/src/index.ts b/src/index.ts index 5e50cc0..84bc8ef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,6 @@ export * from './hooks/use-async-effect'; +export * from './hooks/use-callback-const'; +export * from './hooks/use-callback-ref'; export * from './hooks/use-click-outside'; export * from './hooks/use-clipboard'; export * from './hooks/use-compare'; @@ -23,3 +25,4 @@ export * from './hooks/use-microtask-effect'; export * from './hooks/use-previous'; export * from './hooks/use-resize-observer'; export * from './hooks/use-timer'; +export * from './hooks/use-value-ref'; From 8ca0423afa3fd7b5f017fc0d7ecb9a18323dc074 Mon Sep 17 00:00:00 2001 From: Ian K Smith Date: Thu, 6 Oct 2022 11:10:36 -0600 Subject: [PATCH 2/2] Update broken imports --- src/hooks/use-dom-event-listeners/index.ts | 2 +- src/hooks/use-intersection-observer/index.ts | 2 +- src/hooks/use-interval/index.ts | 2 +- src/hooks/use-is-mounted/index.ts | 2 +- src/hooks/use-measurement/index.ts | 2 +- src/hooks/use-timer/index.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hooks/use-dom-event-listeners/index.ts b/src/hooks/use-dom-event-listeners/index.ts index e2bd93b..0e94c99 100644 --- a/src/hooks/use-dom-event-listeners/index.ts +++ b/src/hooks/use-dom-event-listeners/index.ts @@ -4,7 +4,7 @@ import { MutableRefObject, RefObject, useEffect, useRef } from 'react'; import { isDocument, isElement, isRefObject, isWindow } from '../../utils/instance-of'; -import { useCallbackConst } from '../use-const'; +import { useCallbackConst } from '../use-callback-const'; export interface AddEventListenerFunction< T extends HTMLElement | Window | Document, diff --git a/src/hooks/use-intersection-observer/index.ts b/src/hooks/use-intersection-observer/index.ts index 1b35b2b..4097573 100644 --- a/src/hooks/use-intersection-observer/index.ts +++ b/src/hooks/use-intersection-observer/index.ts @@ -1,7 +1,7 @@ import { DependencyList, useEffect, useRef, useState } from 'react'; import { ElementOrRef, resolveElement } from '../../utils/element-refs'; -import { useCallbackConst } from '../use-const'; +import { useCallbackConst } from '../use-callback-const'; import { useIsMounted } from '../use-is-mounted'; function hasIntersectionObserver() { diff --git a/src/hooks/use-interval/index.ts b/src/hooks/use-interval/index.ts index 63443c2..4df11b8 100644 --- a/src/hooks/use-interval/index.ts +++ b/src/hooks/use-interval/index.ts @@ -1,6 +1,6 @@ import { DependencyList, EffectCallback, useEffect, useRef } from 'react'; -import { useCallbackConst } from '../use-const'; +import { useCallbackConst } from '../use-callback-const'; import { useEffectTrigger } from '../use-effect-trigger'; import { useInitialRender } from '../use-initial-render'; diff --git a/src/hooks/use-is-mounted/index.ts b/src/hooks/use-is-mounted/index.ts index 0d325c3..b706858 100644 --- a/src/hooks/use-is-mounted/index.ts +++ b/src/hooks/use-is-mounted/index.ts @@ -1,6 +1,6 @@ import { useRef } from 'react'; -import { useCallbackConst } from '../use-const'; +import { useCallbackConst } from '../use-callback-const'; import { useEffectOnce } from '../use-effect-once'; /** diff --git a/src/hooks/use-measurement/index.ts b/src/hooks/use-measurement/index.ts index 7662863..1abf777 100644 --- a/src/hooks/use-measurement/index.ts +++ b/src/hooks/use-measurement/index.ts @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react'; import { ReactRef } from '../../utils/element-refs'; -import { useCallbackConst } from '../use-const'; +import { useCallbackConst } from '../use-callback-const'; import { useIsomorphicLayoutEffect } from '../use-isomorphic-layout-effect'; import { useResizeObserver } from '../use-resize-observer'; diff --git a/src/hooks/use-timer/index.ts b/src/hooks/use-timer/index.ts index 32ddc82..3e524d7 100644 --- a/src/hooks/use-timer/index.ts +++ b/src/hooks/use-timer/index.ts @@ -1,7 +1,7 @@ import { DependencyList, EffectCallback, useEffect, useMemo, useReducer, useRef } from 'react'; +import { useCallbackConst } from '../use-callback-const'; import { useCompare } from '../use-compare'; -import { useCallbackConst } from '../use-const'; export interface TimerHook { /**