Skip to main content

Common Hooks

A collection of reusable React hooks for common functionality across web and mobile platforms.

Purpose

This library provides a set of utility hooks that work consistently across React (web) and React Native (mobile) platforms, offering common functionality like event handling, window sizing, and lifecycle management.

Features

  • Cross-platform compatibility: Works on both React (web) and React Native (mobile)
  • Event handling: Automatic cleanup for event listeners and proper event typing
  • Lifecycle management: Async effects, one-time effects, and layout effects
  • Size tracking: Window and element size tracking with optional debouncing
  • State management: Previous value tracking and URL search parameter management

Installation

npm install @haus-storefront-react/common-hooks

Note: This is not a public package. Contact the Haus Tech Team for access.

API Reference

useAsyncEffect

Runs an async effect with proper cleanup handling. Supports both Promise and AsyncGenerator return types.

Parameters

ParameterTypeRequiredDescription
effect() => Promise<void> | AsyncGenerator<void, void, void>YesAsync function or async generator to run
depsDependencyListNoOptional dependency array (defaults to undefined)

Returns

void - No return value

useChangeEvent

Creates a memoized change event handler with proper event typing.

Parameters

ParameterTypeRequiredDescription
handlerChangeEventHandler<T>YesChange event handler function
TElementNoGeneric type parameter for the element type (defaults to Element)

Returns

ChangeEventHandler<T> - Memoized change event handler

useInputChangeEvent

Specialized change handler hook for form elements. It extracts and forwards only event.target.value from input, textarea, and select elements.

Parameters

ParameterTypeRequiredDescription
handler(value: string) => voidYesCallback receiving the input value

Returns

ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement> - Memoized input change handler

useEffectOnce

Runs an effect only once on mount. If dependencies are provided, runs when all dependencies are defined and not null.

Parameters

ParameterTypeRequiredDescription
effectEffectCallbackYesEffect callback function
depsDependencyListNoOptional dependency array (defaults to empty array)

Returns

void - No return value

useElementSize

Tracks the size of a DOM element with optional padding exclusion and automatic resize detection.

Parameters

ParameterTypeRequiredDescription
includePaddingbooleanNoIf true, calculates size excluding padding (subtracts padding from dimensions). Defaults to false which includes padding in the size calculation.

Returns

[ref: (arg: unknown) => void, size: Size] - Tuple containing ref callback and size object

useEventListener

Adds event listeners with automatic cleanup. Supports Window, Document, HTMLElement, and MediaQueryList targets.

Parameters

ParameterTypeRequiredDescription
eventNameKYesEvent name from WindowEventMap, DocumentEventMap, HTMLElementEventMap, or MediaQueryListEventMap
handler(event: EventType) => voidYesEvent handler function
elementRefObject<T>NoOptional ref object for element-specific events (defaults to undefined, uses window)
optionsboolean | AddEventListenerOptionsNoOptional addEventListener options

Returns

void - No return value

useIsomorphicLayoutEffect

Layout effect that works on both web and mobile platforms. Uses useLayoutEffect on web and useEffect on React Native.

Parameters

ParameterTypeRequiredDescription
effectEffectCallbackYesEffect callback function
depsDependencyListNoOptional dependency array

Returns

void - No return value

useKeyDown

Handles keyboard events for specific keys with optional preventDefault and stopPropagation options.

Parameters

ParameterTypeRequiredDescription
keystring | string[]YesKey name(s) to listen for
handlerKeyDownHandlerYesKeyboard event handler function
optionsKeyDownOptionsNoOptional configuration object

Options Object

interface KeyDownOptions {
preventDefault?: boolean
stopPropagation?: boolean
}

Returns

KeyDownHandler - Memoized keyboard event handler

usePreviousPersistent

Tracks the previous value of a variable using deep equality comparison.

Parameters

ParameterTypeRequiredDescription
valueTYesCurrent value to track

Returns

T \| null - Previous value or null if no previous value exists

useSearchParams

Manages URL search parameters with automatic synchronization to browser history.

Parameters

ParameterTypeRequiredDescription
onParamsChangeParamsChangeCallbackNoOptional callback function called when search params change

Returns

[URLSearchParams, UpdateSearchParams] - Tuple containing current search params and update function

useWindowSize

Tracks window size with optional debouncing for performance optimization.

Parameters

ParameterTypeRequiredDescription
debounceValuenumberNoOptional debounce delay in milliseconds (web only, ignored in React Native)

Returns

WindowSize - Object containing width and height

Note: In React Native, this hook uses useWindowDimensions and does not support debouncing. The debounceValue parameter is ignored in React Native.

Basic Usage

Simple Event Listener

import { useEventListener } from '@haus-storefront-react/common-hooks'

function MyComponent() {
useEventListener('scroll', () => {
console.log('Page scrolled')
})

return <div>Scroll to see console output</div>
}

One-Time Effect

import { useEffectOnce } from '@haus-storefront-react/common-hooks'

function MyComponent() {
useEffectOnce(() => {
console.log('Component mounted once')
})

return <div>Check console</div>
}

Search Params

import { useSearchParams } from '@haus-storefront-react/common-hooks'

function MyComponent() {
const [searchParams, setSearchParams] = useSearchParams((newParams) => {
console.log('Params changed:', newParams.toString())
})

const updateParam = (key, value) => {
setSearchParams({ ...Object.fromEntries(searchParams), [key]: value })
}

return (
<div>
<button onClick={() => updateParam('filter', 'active')}>
Filter Active
</button>
</div>
)
}

Advanced Usage

Async Effect with Cleanup

import { useAsyncEffect } from '@haus-storefront-react/common-hooks'

function DataComponent({ userId }) {
useAsyncEffect(async () => {
const controller = new AbortController()

const data = await fetch(`/api/users/${userId}`, {
signal: controller.signal,
}).then((res) => res.json())

// Handle data
console.log('Data loaded:', data)

return () => {
controller.abort()
}
}, [userId])

return <div>Loading user data...</div>
}

Keyboard Event Handling

import { useKeyDown } from '@haus-storefront-react/common-hooks'

function KeyboardComponent() {
const handleEscape = useKeyDown(
'Escape',
(event) => {
console.log('Escape pressed')
// Close modal, reset form, etc.
},
{
preventDefault: true,
stopPropagation: true,
},
)

const handleMultipleKeys = useKeyDown(['Enter', 'Space'], (event) => {
if (event.key === 'Enter') {
console.log('Enter pressed')
} else {
console.log('Space pressed')
}
})

return (
<div
onKeyDown={(e) => {
handleEscape(e)
handleMultipleKeys(e)
}}
>
Press Escape, Enter, or Space
</div>
)
}

Hooks Composition

import {
useEventListener,
usePreviousPersistent,
useWindowSize,
} from '@haus-storefront-react/common-hooks'

function useWindowResize() {
const { width, height } = useWindowSize(100) // 100ms debounce
const previousSize = usePreviousPersistent({ width, height })

useEventListener('resize', () => {
if (
previousSize &&
(width !== previousSize.width || height !== previousSize.height)
) {
console.log('Size changed')
}
})

return {
size: { width, height },
previousSize,
hasChanged:
previousSize &&
(width !== previousSize.width || height !== previousSize.height),
}
}

function MyComponent() {
const { size, hasChanged } = useWindowResize()

return (
<div>
Window: {size.width} x {size.height}
{hasChanged && <div>Size changed!</div>}
</div>
)
}

Made with ❤️ by Haus Tech Team