@qazuor/react-hooks
Version:
A comprehensive collection of production-ready React hooks for modern web applications. Features type-safe implementations, extensive testing, and zero dependencies. Includes hooks for state management, browser APIs, user interactions, and development uti
83 lines (72 loc) • 2.54 kB
text/typescript
import { useCallback, useEffect, useRef } from 'react';
type LogLevel = 'info' | 'warn' | 'error' | 'debug';
type LoggerOptions = {
/** Log level to use. Defaults to 'info'. */
level?: LogLevel;
/** Whether to include timestamps in logs. Defaults to true. */
timestamp?: boolean;
/** Whether logging is enabled. Defaults to true. */
enabled?: boolean;
/** Custom formatter for the log message. */
formatter?: (label: string, value: unknown) => string;
};
/**
* useLogger
*
* @description Logs a message to the console whenever the provided `value` changes.
* This can be useful for debugging or tracking state changes.
*
* @param {string} label - A string label to precede the value in the console log.
* @param {unknown} value - The value to log whenever it changes.
* @param {LoggerOptions} [options] - Optional configuration for the logger.
* @returns {() => void} - A function to manually trigger logging.
*
* @example
* ```ts
* useLogger('Current count', count);
* ```
*/
export function useLogger(label: string, value: unknown, options: LoggerOptions = {}) {
const { level = 'info', timestamp = true, enabled = true, formatter } = options;
const prevValue = useRef<unknown>(null);
const isFirstRender = useRef(true);
const getTimestamp = useCallback(() => {
if (!timestamp) return '';
return `[${new Date().toISOString()}] `;
}, [timestamp]);
const formatMessage = useCallback(
(msg: unknown) => {
if (formatter) {
return formatter(label, msg);
}
return `${getTimestamp()}[${label}] ${JSON.stringify(msg)}`;
},
[label, getTimestamp, formatter]
);
const log = useCallback(() => {
if (!enabled) return;
const message = formatMessage(value);
switch (level) {
case 'warn':
console.warn(message);
break;
case 'error':
console.error(message);
break;
case 'debug':
console.debug(message);
break;
default:
console.info(message);
}
}, [enabled, level, value, formatMessage]);
useEffect(() => {
// Log on first render or when value changes
if (isFirstRender.current || value !== prevValue.current) {
log();
isFirstRender.current = false;
prevValue.current = value;
}
}, [value, log]);
return log;
}