Hooks
The Hooks namespace includes functions to create user hooks:
useClickOutside- perform the effect when the user clicks outside the elementuseCompose- create a composed functionuseCookie- manage a cookieuseCurry- create a curried functionuseDebounce- create a debounced functionuseEvent- create an event listeneruseId- create id for the elementuseInterval- create an intervaluseMediaQuery- check a media queryuseMemo- memoization functionusePipe- create a piped functionuseQueue- create a queueuseState- create a state variable and a function to change ituseThrottle- create a throttled functionuseToggle- create a toggle function
Installation
Section titled “Installation”Metro UI already includes the Hooks.
You can use it without any additional installation, but if you want to use it in your project, you can install it with package manager:
npm install @olton/hookspnpm install @olton/hooksyarn add @olton/hooksor use CDN:
<script type="module"> import * as Hooks from "https://esm.run/@olton/hooks";</script>useClickOutside()
Section titled “useClickOutside()”useClickOutside is a hook to detect when a click occurs outside of a given DOM element.
The function accepts a target element and a callback function.
If a click event happens outside of the specified element, the callback will be executed.
const myDiv = document.getElementById('my-div');const handleOutsideClick = () => { console.log('Clicked outside the div!');};
const { attach, detach } = useClickOutside(myDiv, handleOutsideClick);
// Attach the click listenerattach();
// Later, if you need to remove the listenerdetach();useCompose()
Section titled “useCompose()”useCompose is a hook for the composition of functions (performance from right to left)
f(g(h(x))) => compose(f, g, h)(x)
const add = (x: number) => x + 1;const multiply = (x: number) => x * 2;const subtract = (x: number) => x - 3;
// f(g(h(x))) => subtract(multiply(add(x)))const composedMath = useCompose(subtract, multiply, add);const result = composedMath(5); // ((5 + 1) * 2) - 3 = 9console.log(result); // Output: 9const trim = (str: string) => str.trim();const toUpperCase = (str: string) => str.toUpperCase();const exclaim = (str: string) => str + '!';
const composedString = useCompose(exclaim, toUpperCase, trim);const message = composedString(" hello world ");console.log(message); // Output: "HELLO WORLD!"// Example 3: No-op (when no functions are provided)const identity = useCompose();console.log(identity(42)); // Output: 42useCookie()
Section titled “useCookie()”The useCookie hook is a simple utility to manage browser cookies.
It allows getting, setting, and deleting cookies in a straightforward way.
Functions Provided:
get: Retrieves the value of the cookie by its name.set: Sets a new value for the cookie with additional options (such as expiration or path).delete: Deletes the cookie by setting a negativemax-age.
Retrieving a Cookie
Section titled “Retrieving a Cookie”const { get } = useCookie('user-token');const token = get();console.log(token); // Prints the cookie value if exists, otherwise nullSetting a Cookie
Section titled “Setting a Cookie”const { set } = useCookie('user-token');set('abc123', { path: '/', expires: new Date(Date.now() + 3600 * 1000) }); // Expires in 1 hourDeleting a Cookie
Section titled “Deleting a Cookie”const { delete: deleteCookie } = useCookie('user-token');deleteCookie();console.log(document.cookie); // The 'user-token' cookie is now deleteduseCurry()
Section titled “useCurry()”Hook for currying a function f(x, y, z) => f(x)(y)(z)
// Example 1: Basic curryingconst add = (x: number, y: number) => x + y;const curriedAdd = useCurry(add);console.log(curriedAdd(2)(3)); // Output: 5// Example 2: String concatenationconst concat = (a: string, b: string, c: string) => a + b + c;const curriedConcat = useCurry(concat);console.log(curriedConcat('Hello')(' ')('World!')); // Output: "Hello World!"// Example 3: No-op (when no arguments are provided)const noop = useCurry();console.log(noop()); // Output: undefineduseDebounce()
Section titled “useDebounce()”Hook for debouncing a function f(x) => useDebounce(f, 1000)(x)
// Example 1: Basic debouncingconst log = (message: string) => console.log(message);const debouncedLog = useDebounce(log, 1000);debouncedLog('Hello'); // Will log "Hello" after 1 second// Example 2: Immediateconst immediateLog = useDebounce(log, 1000, { immediate: true });immediateLog('Immediate Hello'); // Will log "Immediate Hello" immediately // Example 3: Canceling const cancelableLog = useDebounce(log, 1000); cancelableLog('Cancel me'); // Will log "Cancel me" after 1 second cancelableLog.cancel(); // Cancels the debounced function// Example 4: No-op (when no arguments are provided)const noop = useDebounce();console.log(noop()); // Output: undefineduseEvent()
Section titled “useEvent()”The useEvent hook is a utility for handling various events and mutations on DOM elements.
It allows you to specify an event type, a target element, and a callback function that will be executed when the event occurs.
Events
Section titled “Events”load- Triggered when the element is loaded.viewport- Triggered when the element enters or exits the viewport.attribute- Triggered when an attribute of the element changes.children- Triggered when the children of the element change.data- Triggered when the data of the element changes.
export enum EVENTS { LOAD = 'load', VIEWPORT = 'viewport', ATTRIBUTE = 'attribute', CHILDREN = 'children', DATA = 'data',}useEvent({ event: EVENTS.LOAD, target: '#myElement', effect: (el) => console.log('Element loaded:', el),});useId()
Section titled “useId()”The hook useId generates a unique ID associated with a given key, utilizing options for customization.
The IDs are stored internally to ensure they are reused unless forceNew is set in the options.
Params:
key- A string or symbol or HTMLElement used to generate the ID.options- Options to customize the generated ID. An object containing:prefix- A string prefix for the ID.divider- A string used to separate parts of the ID.forceNew- A boolean indicating whether to force a new ID. Iftrue, forces the generation of a new ID even if one already exists for the key.
// Generate an ID for a string keyconst id1 = useId("my-key");console.log(id1); // Outputs: "id-my_key-0" (depends on current counter)// Generate an ID with customization optionsconst id2 = useId("customElement", { prefix: "custom", divider: "-", forceNew: true});// Outputs: "custom-customElement-0" (depends on current counter)console.log(id2);// Reuse an existing ID for the same keyconst id1 = useId("my-key");const id3 = useId("my-key");console.log(id3 === id1); // true// Generate IDs for different key typesconst id4 = useId(symbolKey);const id5 = useId(domElement);console.log(id4); // Example: "id-symbol-1"console.log(id5); // Example: "id-div-2"useInterval()
Section titled “useInterval()”The useInterval hook is a utility for creating and managing intervals in JavaScript.
const { start, stop } = useInterval(() => { console.log('Interval triggered');}, 1000);
start(); // Starts the intervalstop(); // Stops the intervaluseMediaQuery()
Section titled “useMediaQuery()”useMediaQuery - a custom hook that listens to changes in a specified media query and returns
whether the media query currently matches.
// Check if the viewport width is 600px or lessconst isSmallScreen = useMediaQuery("(max-width: 600px)");console.log(isSmallScreen); // true or false depending on the screen size// Check for a dark mode preferenceconst prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");console.log(prefersDarkMode); // true if user prefers dark modeuseMemo()
Section titled “useMemo()”useMemo - a hook to memoize the result of a function, with an optional maximum cache size.
const add = (a: number, b: number): number => a + b;const memoizedAdd = useMemo(add, { maxSize: 3 });
// Memoized function callsconsole.log(memoizedAdd(1, 2)); // 3, computedconsole.log(memoizedAdd(1, 2)); // 3, from cache
// Clear the cachememoizedAdd.clearCache();console.log(memoizedAdd(1, 2)); // 3, computed again after cache clearusePipe()
Section titled “usePipe()”usePipe - creates a pipeline of functions where the output of one function is passed as the input to the next.
This utility supports 0, 1, 2, or more functions as input:
- If no functions are provided, it returns an identity function.
- If one function is provided, it returns that function.
- If two functions are provided, it optimizes the pipeline for two functions.
- For more than two functions, it chains all functions in order.
// Piping two functions: adding 1 and doubling the resultconst addOne = (x: number) => x + 1;const double = (x: number) => x * 2;const piped = usePipe(addOne, double);console.log(piped(2)); // Output: 6// Using a function pipeline with stringsconst toUpperCase = (str: string) => str.toUpperCase();const appendExclamation = (str: string) => `${str}!`;const piped = usePipe(toUpperCase, appendExclamation);console.log(piped('hello')); // Output: 'HELLO!'// With no functions passedconst piped = usePipe();console.log(piped('unchanged')); // Output: 'unchanged'// Chaining multiple functionsconst increment = (x: number) => x + 1;const square = (x: number) => x * x;const half = (x: number) => x / 2;const piped = usePipe(increment, square, half);console.log(piped(2)); // Output: 4.5useQueue()
Section titled “useQueue()”useQueue - A utility hook for managing a queue of items.
Provides methods to add, remove, and inspect items in the queue.
The hook returns function Object() { [native code] }. The methods to interact with the queue:
enqueue(item: T): number- Adds an item to the queue and returns the new size of the queue.dequeue(): T | undefined- Removes and returns the item at the front of the queue. Returnsundefinedif the queue is empty.peek(): T | null- Returns the item at the front of the queue without removing it. Returnsnullif the queue is empty.size(): number- Returns the number of items in the queue.isEmpty(): boolean- Checks if the queue is empty and returns a boolean value.clear(): void- Clears all items in the queue.
// Create a new queueconst { enqueue, dequeue, peek, size, isEmpty, clear } = useQueue<number>();
// Add items to the queueenqueue(1); // Queue: [1], returns 1enqueue(2); // Queue: [1, 2], returns 2
// Check the first itemconsole.log(peek()); // Output: 1
// Remove the first itemconsole.log(dequeue()); // Output: 1, Queue: [2]
// Check the size of the queueconsole.log(size()); // Output: 1
// Check if the queue is emptyconsole.log(isEmpty()); // Output: false
// Clear the queueclear(); // Queue: []console.log(isEmpty()); // Output: trueuseState()
Section titled “useState()”useState - A custom hook that manages state, similar to React’s useState.
It allows tracking of state values and processes an optional callback when the state changes.
Params:
initialValue- The initial value of the state.onChange- An optional callback function that is called when the state changes. It receives the new and old values as arguments.
const onStateChange = (newValue: number, oldValue: number) => { console.log(`State changed from ${oldValue} to ${newValue}`);};
const [count, setCount] = useState(0, onStateChange);
console.log(+count); // Logs: 0
setCount(5); // Logs: "State changed from 0 to 5"
setCount(prev => prev + 1); // Logs: "State changed from 5 to 6"console.log(+count); // Logs: 6
console.log(String(count)); // Logs: "6"useThrottle()
Section titled “useThrottle()”useThrottle - Creates a throttled version of a given function that limits its execution to at most once every wait milliseconds.
Supports options to control whether the function executes on the leading and/or trailing edge of the timeout.
// Throttle a function that logs a messageconst throttledLog = useThrottle((message) => console.log(message), 1000, { leading: true });throttledLog("Hello"); // Logs "Hello" immediatelythrottledLog("World"); // Ignored, as it's within the 1000ms wait period
setTimeout(() => { throttledLog("Goodbye"); // Logs "Goodbye" after 1000ms}, 1500);// Cancel pending executionconst throttledFn = useThrottle(() => console.log("Executed"), 2000);throttledFn();throttledFn.cancel(); // Prevents the execution of the trailing calluseToggle()
Section titled “useToggle()”useToggle - A custom hook that provides a simple way to toggle a boolean state value.
It returns the current state and a function to toggle it.
// Basic usageconst toggle = useToggle();console.log(toggle.get()); // falsetoggle.toggle(); // truetoggle.set(false); // false// Initialize with a custom starting valueconst toggle = useToggle(true);console.log(toggle.get()); // truetoggle.toggle(); // falsetoggle.set(true); // true