@liberfi.io/hooks
v0.1.89
Published
A collection of framework-agnostic React utility hooks used across the LiberFi frontend. Provides common patterns — boolean state, stable callback refs, resize observation, periodic ticking, and a shared event bus — so that consuming packages don't reinve
Downloads
10,061
Readme
@liberfi.io/hooks
A collection of framework-agnostic React utility hooks used across the LiberFi frontend. Provides common patterns — boolean state, stable callback refs, resize observation, periodic ticking, and a shared event bus — so that consuming packages don't reinvent them.
Design Philosophy
- One hook, one file — each hook lives in its own module with a single, focused responsibility.
- Stable references — actions and callbacks are memoised via
useCallback/useRefto prevent unnecessary consumer re-renders. - SSR-safe —
useSafeLayoutEffectguardsuseLayoutEffectbehind a runtime check; other hooks use onlyuseEffect. - Shared timer —
useTickmultiplexes all subscribers through a singleGlobalTimersingleton, avoiding per-hook intervals. - Minimal dependencies — only
eventemitter3and@liberfi.io/utilsat runtime; throttle is implemented internally.
Installation
pnpm add @liberfi.io/hooksPeer dependencies
The consumer must provide:
| Package | Version |
| ------- | ------- |
| react | >=18 |
API Reference
Hooks
useBoolean
Manage a boolean state with convenience setters.
function useBoolean(initialValue?: boolean): UseBooleanReturn;
type UseBooleanReturn = [
boolean,
{ setTrue: () => void; setFalse: () => void; toggle: () => void },
];useCallbackRef
Persist a callback reference that always points to the latest function, while returning a stable callable.
function useCallbackRef<T extends (...args: any[]) => any>(
fn: T | undefined,
deps?: React.DependencyList,
): T;useIsMounted
Returns a function that reports whether the component is currently mounted.
function useIsMounted(): () => boolean;useValueRef
Returns a ref that always reflects the latest value (updated synchronously on render).
function useValueRef<T>(value: T): RefObject<T>;useSafeLayoutEffect
useLayoutEffect in the browser, useEffect on the server. Drop-in replacement to suppress SSR warnings.
const useSafeLayoutEffect: typeof useLayoutEffect;useTick
Calls a callback at a specified interval, powered by a shared GlobalTimer singleton.
function useTick(callback: TickCallback, interval?: number): void;
type TickEvent = { delta: number; now: number };
type TickCallback = (event: TickEvent) => void;| Parameter | Type | Default | Description |
| ---------- | -------------- | ------- | -------------------------------------- |
| callback | TickCallback | — | Called each tick with { delta, now } |
| interval | number | 1000 | Milliseconds between ticks |
useTickAge
Returns the elapsed milliseconds since a given birthday, updated every tick.
function useTickAge(birthday?: number | Date, interval?: number): number;| Parameter | Type | Default | Description |
| ---------- | ---------------- | ------------ | ------------------- |
| birthday | number \| Date | Date.now() | Reference timestamp |
| interval | number | 1000 | Tick interval in ms |
useResizeObserver
Observes an element's size via the ResizeObserver API.
function useResizeObserver<T extends HTMLElement>(
options: UseResizeObserverOptions<T>,
): Size;When onResize is provided, the hook delegates to it instead of updating internal state (no re-renders).
useThrottledResizeObserver
Throttled variant of useResizeObserver.
function useThrottledResizeObserver<T extends HTMLElement>(
options: UseThrottledResizeObserverOptions<T>,
): Size;useEventEmitter
Returns a global EventEmitter singleton (from eventemitter3) managed by an internal DI container.
function useEventEmitter(): EventEmitter;Types
| Type | Description |
| -------------------------------------- | ----------------------------------------------------------------------------------- |
| UseBooleanReturn | Return type of useBoolean |
| Size | { width: number \| undefined; height: number \| undefined } |
| UseResizeObserverOptions<T> | Options for useResizeObserver: ref, onResize?, box? |
| UseThrottledResizeObserverOptions<T> | Options for useThrottledResizeObserver: ref, box?, throttleMs? (default 50) |
| TickEvent | Tick payload: { delta: number; now: number } |
| TickCallback | (event: TickEvent) => void |
Constants
| Name | Type | Description |
| --------- | -------- | ------------------------------------ |
| version | string | Current package version ("0.1.24") |
Usage Examples
Basic boolean toggle
import { useBoolean } from "@liberfi.io/hooks";
function Panel() {
const [isOpen, { toggle, setFalse }] = useBoolean(false);
return (
<div>
<button onClick={toggle}>Toggle</button>
{isOpen && <div onClose={setFalse}>Content</div>}
</div>
);
}Periodic countdown
import { useTickAge } from "@liberfi.io/hooks";
function Timer({ startedAt }: { startedAt: number }) {
const elapsed = useTickAge(startedAt, 1000);
const seconds = Math.floor(elapsed / 1000);
return <span>{seconds}s elapsed</span>;
}Resize-aware component
import { useRef } from "react";
import { useResizeObserver } from "@liberfi.io/hooks";
function Card() {
const ref = useRef<HTMLDivElement>(null);
const { width = 0 } = useResizeObserver({ ref });
return <div ref={ref}>{width > 600 ? <WideLayout /> : <NarrowLayout />}</div>;
}Cross-component event bus
import { useEffect } from "react";
import { useEventEmitter } from "@liberfi.io/hooks";
function Sender() {
const ee = useEventEmitter();
return <button onClick={() => ee.emit("refresh")}>Refresh</button>;
}
function Receiver() {
const ee = useEventEmitter();
useEffect(() => {
const handler = () => console.log("refreshed");
ee.on("refresh", handler);
return () => {
ee.off("refresh", handler);
};
}, [ee]);
return null;
}Future Improvements
- Evaluate whether
version.tstop-level side effect should be lazy-initialised.
