@denovo-hellas/common
v1.2.3
Published
Common functions and hooks
Downloads
469
Readme
useArray
Hook
The useArray
hook provides a set of utility functions to manage and manipulate an array state in a React component. It leverages the useState
hook to maintain the state of the array and offers methods for common operations like adding, filtering, updating, and removing elements from the array.
TypeScript Definition
function useArray<T>(defaultValue: T[]): {
data: T[];
set: React.Dispatch<React.SetStateAction<T[]>>;
push: (element: T) => void;
filter: (callback: (element: T, index: number, array: T[]) => boolean) => void;
update: (index: number, newElement: T) => void;
remove: (index: number) => void;
clear: () => void;
updateAll: (callback: (element: T, index: number, array: T[]) => T) => void;
}
Usage
import useArray from './useArray';
function MyComponent() {
const { data, push, remove, update, clear, filter, updateAll } = useArray<number>([]);
// Example usage:
push(5); // Adds 5 to the array
update(0, 10); // Updates the first element to 10
remove(0); // Removes the first element
clear(); // Clears the entire array
filter((element) => element > 10); // Keeps elements greater than 10
updateAll((element) => element * 2); // Doubles every element in the array
return (
<div>
{data.map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
);
}
Parameters
defaultValue: T[]
: The initial value of the array. It sets up the initial state of the array.
Returns
The useArray
hook returns an object containing the following properties and methods:
Properties
data: T[]
: The current state of the array.set: React.Dispatch<React.SetStateAction<T[]>>
: A setter function to directly update the state of the array, similar touseState
.
Methods
push(element: T): void
- Adds a new element to the end of the array.
- Parameters:
element
- The element to add to the array.
filter(callback: (element: T, index: number, array: T[]) => boolean): void
- Filters the array based on the provided callback function, keeping only the elements for which the callback returns
true
. - Parameters:
callback
- A function that receives each element, its index, and the entire array, and returns a boolean indicating whether the element should remain in the array.
- Filters the array based on the provided callback function, keeping only the elements for which the callback returns
update(index: number, newElement: T): void
- Updates the element at the specified index with a new element.
- Parameters:
index
- The index of the element to update.newElement
- The new element to replace the existing one.
remove(index: number): void
- Removes the element at the specified index from the array.
- Parameters:
index
- The index of the element to remove.
clear(): void
- Clears the entire array, setting it to an empty array.
updateAll(callback: (element: T, index: number, array: T[]) => T): void
- Updates all elements in the array using the provided callback function.
- Parameters:
callback
- A function that receives each element, its index, and the entire array, and returns a new value for each element.
Example Use Cases
- Managing a dynamic list of items, such as a to-do list where you can add, remove, and update tasks.
- Filtering or transforming data, for example, filtering out specific values or modifying all elements with a given transformation.
Notes
- This hook makes managing arrays in React state more convenient by abstracting common operations into easy-to-use functions.
- The
useArray
hook can be used with any typeT
, making it a generic and reusable utility for managing arrays of different types (e.g., strings, numbers, objects).
useAsyncOnce
Hook
Function Signature
export function useAsyncOnce<T extends (...args: any[]) => Promise<any>>(asyncFunction: T): UseAsyncOnceProps<T> { ... }
Parameters
asyncFunction
: An asynchronous function of typeT
that you want to execute. This function can take any number of arguments and must return aPromise
.
Returns
An object of type UseAsyncOnceProps<T>
containing:
call
: A function that invokesasyncFunction
. This function accepts the same parameters asasyncFunction
.isExecuting
: A boolean value that indicates whetherasyncFunction
is currently being executed.
Usage Example
import React from 'react';
import { useAsyncOnce } from '@/hooks/useAsyncOnce';
async function fetchData() {
// Simulating an async data fetch
return await fetch('https://api.example.com/data');
}
function MyComponent() {
const { call, isExecuting } = useAsyncOnce(fetchData);
return (
<div>
<button onClick={call} disabled={isExecuting}>
{isExecuting ? 'Loading...' : 'Fetch Data'}
</button>
</div>
);
}
Detailed Explanation
State Management
isExecuting
: A boolean state, managed usinguseState
, that tracks whether theasyncFunction
is currently being executed. It is initialized tofalse
.
call
Function
useCallback
is used to memoize thecall
function, ensuring that it only changes whenasyncFunction
orisExecuting
changes.- The
call
function performs the following:- Checks if
isExecuting
istrue
. If it is, the function returns early, preventing multiple simultaneous executions. - Sets
isExecuting
totrue
before callingasyncFunction
. - Uses a
try-catch-finally
block to:- Await the execution of
asyncFunction
. - Log an error to the console if the call fails.
- Reset
isExecuting
tofalse
when the function completes, regardless of success or failure.
- Await the execution of
- Checks if
Benefits
- Prevents multiple simultaneous calls: By using
isExecuting
, the hook ensures thatasyncFunction
isn't called again until the previous execution finishes. - Handles state management: Automatically updates
isExecuting
to inform your components when the function is running.
useDebounce
Hook
The useDebounce
hook is a utility for debouncing a callback function, which limits the rate at which the function is invoked. This is useful in scenarios where frequent events (such as typing or scrolling) would otherwise cause a function to run too many times. The hook ensures that the callback
is only called after the specified delay
has elapsed since the last time the hook dependencies were updated.
Function Signature
export default function useDebounce({ callback, delay, dependencies }: UseDebounceProps): void
Parameters
callback
:Function
The function to be debounced. This is the function that will be called after the specifieddelay
if no dependencies change during that time.delay
:number
The delay in milliseconds that the hook will wait after the last change in dependencies before callingcallback
.dependencies
:Array<any>
An array of dependencies that, when changed, will reset the debounce timer. This is similar to the dependency array inuseEffect
.
Return Value
The useDebounce
hook does not return a value.
How It Works
useTimeout
is used internally to set up a timer. This timer is configured to trigger thecallback
function after thedelay
.reset
andclear
are utility functions provided byuseTimeout
:reset
restarts the timer every time there is a change in any of thedependencies
.clear
stops the timer when the component is unmounted.
Example Usage
import useDebounce from './useDebounce';
function SearchComponent({ searchTerm }) {
const debouncedSearch = () => {
// Perform search logic here, e.g., API call
console.log('Searching:', searchTerm);
};
// Set up debounce with a 500ms delay
useDebounce({
callback: debouncedSearch,
delay: 500,
dependencies: [searchTerm],
});
return <div>{/* Your component UI */}</div>;
}
In this example:
debouncedSearch
is only called 500ms after the lastsearchTerm
update.- If
searchTerm
changes before 500ms have passed, the timer resets.
useTimeout
Hook
The useTimeout
hook provides a utility for managing a timeout in React. It allows you to set a timeout that will execute a callback function after a specified delay and offers methods to reset or clear the timeout.
Function Signature
export default function useTimeout({ callback, delay }: UseTimeoutProps): { reset: () => void; clear: () => void }
Parameters
callback
:Function
The function to be executed after the specifieddelay
. This callback is invoked only once per timeout interval, or each timereset
is called.delay
:number
The amount of time, in milliseconds, to wait before calling thecallback
function.
Return Value
The useTimeout
hook returns an object with the following methods:
reset
:Function
A function to reset the timeout. This will clear the existing timeout (if any) and start a new one based on thedelay
parameter.clear
:Function
A function to clear the timeout. This stops the timeout from executing thecallback
function if it hasn’t already executed.
How It Works
Internally, the hook manages a timeout using the following techniques:
useRef
is used to store references to thecallback
andtimeout
.useCallback
memoizes theset
,clear
, andreset
functions to ensure that they are stable across renders.useEffect
:- Updates
callbackRef
whenevercallback
changes, ensuring the latest function is called even if the timeout is still active. - Automatically sets the timeout when the component mounts and clears it on unmount or if
delay
changes.
- Updates
Example Usage
import useTimeout from './useTimeout';
function Notification({ message, duration }) {
const { reset, clear } = useTimeout({
callback: () => {
alert('Timeout expired!');
},
delay: duration,
});
return (
<div>
<p>{message}</p>
<button onClick={reset}>Reset Timeout</button>
<button onClick={clear}>Clear Timeout</button>
</div>
);
}
In this example:
- A timeout is set to show an alert after
duration
milliseconds. - The "Reset Timeout" button restarts the timeout when clicked, while the "Clear Timeout" button stops the timeout, preventing the alert from being displayed.
useEventListener
Hook
The useEventListener
hook is a custom React hook that simplifies attaching and managing event listeners on a specified element. It supports dynamically updating the callback function and ensures cleanup on unmount, making it especially useful for handling DOM events in React.
Function Signature
export function useEventListener({ eventType, callback, element }: UseEventListenerProps): void
Parameters
eventType
:string
The type of event to listen for (e.g.,"click"
,"scroll"
,"resize"
).callback
:Function
The function to be executed when the event is triggered. The callback receives the event object as its argument.element
:RefObject<HTMLElement> | Window | null
The target element to which the event listener will be attached. This can be a Reactref
for a DOM element,window
, ornull
(in which case no event listener is attached).
Return Value
This hook does not return any value.
How It Works
callbackRef
is auseRef
hook that holds a reference to the latestcallback
function, ensuring that the most recent version is called without needing to re-register the event listener each timecallback
updates.useEffect
:- Updates
callbackRef.current
whenevercallback
changes. - Registers the event listener on the specified
element
:- For
window
elements, it directly attaches the listener. - For DOM elements passed as
ref
, it useselement.current
to add and remove the listener.
- For
- Cleans up the event listener on component unmount or when
eventType
orelement
changes.
- Updates
Example Usage
import { useRef } from 'react';
import { useEventListener } from './useEventListener';
function ClickTracker() {
const divRef = useRef(null);
useEventListener({
eventType: 'click',
callback: (e) => console.log('Div clicked!', e),
element: divRef,
});
return <div ref={divRef} style={{ width: '200px', height: '200px', background: 'lightblue' }}>Click me!</div>;
}
In this example:
- The
useEventListener
hook adds a click event listener to adiv
element, which logs a message to the console each time thediv
is clicked. - The hook ensures that the event listener is cleaned up if the component unmounts or the
eventType
orelement
changes.
useStateWithHistory
Hook
The useStateWithHistory
hook provides a way to manage state with history tracking, allowing you to navigate backward and forward through previous state values. This is useful in scenarios where users might want to undo or redo actions, similar to browser navigation or an editor's history feature.
## Function Signature
```typescript
export default function useStateWithHistory<T>({
defaultValue,
capacity = 10,
}: StateWithHistoryProps<T>): StateWithHistory<T>
Parameters
defaultValue
:T
The initial value of the state.capacity
:number
(optional, default =10
)
The maximum number of historical states to keep in memory. When the history exceeds this capacity, the oldest entries are removed.
Return Value
The hook returns an object with the following properties and functions:
value
:T
The current state value.set
:(v: T) => void
Function to set a new state value. If the new value is different from the current state, it is added to the history.history
:T[]
An array representing the history of state values.pointer
:number
The current position in the history, indicating which version of the state is currently active.back
:() => void
Function to move one step back in the history. If already at the oldest state, it has no effect.forward
:() => void
Function to move one step forward in the history. If already at the latest state, it has no effect.go
:(index: number) => void
Function to go to a specific position in the history by index. If the index is out of range, it has no effect.
How It Works
- State Management: The
useState
hook manages the primary state (value
). - History Tracking:
historyRef
holds the array of historical state values.pointerRef
keeps track of the current position withinhistoryRef
.- The
set
function updates the state and manages the history, clearing any "future" states if a new value is set after moving back in history.
- Capacity Management: When the number of historical states exceeds
capacity
, the oldest state is removed.
Example Usage
import useStateWithHistory from './useStateWithHistory';
function Counter() {
const {
value,
set,
history,
pointer,
back,
forward,
go,
} = useStateWithHistory({ defaultValue: 0, capacity: 5 });
return (
<div>
<p>Current Value: {value}</p>
<button onClick={() => set(value + 1)}>Increment</button>
<button onClick={() => set(value - 1)}>Decrement</button>
<button onClick={back} disabled={pointer <= 0}>Undo</button>
<button onClick={forward} disabled={pointer >= history.length - 1}>Redo</button>
<p>History: {history.join(', ')}</p>
</div>
);
}
In this example:
Increment
andDecrement
buttons modify the current state.Undo
andRedo
buttons navigate backward and forward through state history, allowing for easy state management and history tracking.- The
history
array shows the current state history, withpointer
indicating the current position in that history.
isOnScreen
Hook
The isOnScreen
hook determines if a specified element is visible on the screen using the Intersection Observer API. This is useful for detecting when an element enters or leaves the viewport, enabling features like lazy loading, animations, or analytics tracking.
## Function Signature
```typescript
export function isOnScreen(ref: RefObject<HTMLElement>, rootMargin = '0px'): boolean
Parameters
ref
:RefObject<HTMLElement>
A React ref object pointing to the DOM element to observe. This ref should be attached to an element in the component.rootMargin
:string
(optional, default ='0px'
)
The margin around the root (viewport) that is used to determine visibility. This parameter accepts values similar to CSS margin (e.g.,'10px 20px'
). Increasing the root margin can trigger visibility checks earlier (when the element is still outside the viewport).
Return Value
isVisible
:boolean
Returnstrue
if the element is currently visible on the screen (within the viewport) andfalse
otherwise.
How It Works
- The hook uses an
IntersectionObserver
to monitor the visibility of the specifiedref
element. - When the element's visibility changes (enters or exits the viewport based on
rootMargin
), the observer's callback updates theisVisible
state. - Cleanup: The observer disconnects automatically when the component unmounts or if
ref
changes, preventing memory leaks.
Example Usage
import { useRef } from 'react';
import { isOnScreen } from './isOnScreen';
function ImageWithLazyLoad() {
const imageRef = useRef(null);
const onScreen = isOnScreen(imageRef, '100px'); // Trigger 100px before entering viewport
return (
<div ref={imageRef} style={{ height: '300px', background: 'lightgray' }}>
{onScreen ? <img src="image.jpg" alt="Lazy loaded image" /> : <p>Scroll to load image</p>}
</div>
);
}
In this example:
- The
isOnScreen
hook detects ifimageRef
is within 100px of the viewport, allowing the image to load just before it enters the screen. - If the element is not in view, a placeholder text is displayed instead.
useAnimatedNumber
Hook
The useAnimatedNumber
hook animates a numeric value from a starting value to a target value over a specified duration. It supports options for decimal values, locale-based formatting, and re-triggering the animation when the element comes into view.
## Function Signature
```typescript
export function useAnimatedNumber(
targetValue: number,
ref: React.RefObject<HTMLElement>,
options: UseAnimatedNumberOptions = {}
): string
Parameters
targetValue
:number
The target value to animate to.ref
:React.RefObject<HTMLElement>
A React ref object pointing to the DOM element that should be observed. The animation can be triggered when this element enters the viewport.options
:UseAnimatedNumberOptions
(optional)
An object to configure animation options.startValue
:number
(default =0
)
The initial value of the animation.duration
:number
(default =1000
)
The duration of the animation in milliseconds.isDecimal
:boolean
(default =false
)
Specifies whether the animated value should be displayed as a decimal.locale
:string
(default ='en'
)
The locale used for formatting the animated number, allowing for proper number formatting based on the user’s locale.retriggerOnView
:boolean
(default =false
)
If set totrue
, the animation re-triggers each time the element enters the viewport.
Return Value
parsedToLocaleNumber
:string
A string representing the animated number formatted to the specified locale.
How It Works
- View Triggering: The hook uses the
isOnScreen
helper to check if the element referenced byref
is in view, triggering the animation when it appears in the viewport. - Animation Calculation:
- Uses
requestAnimationFrame
to update the value over time. - Calculates progress based on the
duration
and animates fromstartValue
totargetValue
. - If
isDecimal
istrue
, the value is formatted as a decimal.
- Uses
- Locale Formatting: The
Intl.NumberFormat
API is used to format the animated value according to the specifiedlocale
. - Re-triggering: The
retriggerOnView
option determines if the animation re-triggers when the element re-enters the viewport.
Example Usage
import { useRef } from 'react';
import { useAnimatedNumber } from './useAnimatedNumber';
function AnimatedCounter() {
const counterRef = useRef(null);
const animatedNumber = useAnimatedNumber(100, counterRef, {
startValue: 0,
duration: 2000,
isDecimal: true,
locale: 'en',
retriggerOnView: true,
});
return (
<div ref={counterRef} style={{ fontSize: '2rem', fontWeight: 'bold' }}>
{animatedNumber}
</div>
);
}
In this example:
- The number animates from
0
to100
over2000
milliseconds, displaying as a decimal with a locale-specific format. - The animation re-triggers each time the element comes back into view.
useDialog
Hook
The useDialog
hook provides a convenient way to manage the open and close states of a dialog component. This hook centralizes the dialog state management, providing functions to easily open, close, and toggle the dialog state.
## Function Signature
```typescript
export function useDialog({ open: openProps = false }: UseDialogProps = {}): {
open: boolean;
setDialogOpen: () => void;
setDialogClose: () => void;
setOpen: (open: boolean) => void;
}
Parameters
props
:UseDialogProps
(optional)
An object to configure the initial dialog state.open
:boolean
(default =false
)
The initial state of the dialog (open or closed).
Return Value
The hook returns an object containing the current dialog state and functions to control it:
open
:boolean
The current open state of the dialog.true
means the dialog is open;false
means it is closed.setDialogOpen
:() => void
A function to set theopen
state totrue
, opening the dialog.setDialogClose
:() => void
A function to set theopen
state tofalse
, closing the dialog.setOpen
:(open: boolean) => void
A function to set theopen
state directly, allowing for more flexible state control.
How It Works
- State Management:
- The
useState
hook initializes the dialog state (open
) based on theopen
parameter inprops
. setOpen
provides a direct way to modify the state.
- The
- Convenience Functions:
setDialogOpen
andsetDialogClose
simplify toggling the dialog, especially useful for event handlers or dialog controls.
Example Usage
import { useDialog } from './useDialog';
function ExampleDialog() {
const { open, setDialogOpen, setDialogClose } = useDialog({ open: false });
return (
<div>
<button onClick={setDialogOpen}>Open Dialog</button>
{open && (
<div className="dialog">
<p>This is the dialog content.</p>
<button onClick={setDialogClose}>Close Dialog</button>
</div>
)}
</div>
);
}
In this example:
Open Dialog
button callssetDialogOpen
to open the dialog.Close Dialog
button inside the dialog callssetDialogClose
to close it.- The
open
variable controls the conditional rendering of the dialog component.