Gathering detailed insights and metrics for @d3vtool/hooks
Gathering detailed insights and metrics for @d3vtool/hooks
Gathering detailed insights and metrics for @d3vtool/hooks
Gathering detailed insights and metrics for @d3vtool/hooks
npm install @d3vtool/hooks
Typescript
Module System
Node Version
NPM Version
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
2
A collection of custom React hooks designed to simplify common tasks in your React applications. Here’s the list of all the hooks:
useStoredHub
is a custom hook that synchronizes a shared state hub with persistent storage across tabs and pages.usePromiseHubAction
is a custom hook that allows you to manually trigger an asynchronous action within a PromiseHub
and provides the current loading state and any errors.useSecId
is a custom hook that returns a function to generate unique string identifiers with customizable length and character set.useForm
is a custom React hook for managing form state, validation, and asynchronous submission. It optimizes performance by minimizing re-renders, updating the component only on validation errors rather than input changes.useDebounce
is a custom React hook that delays the execution of a function until after a specified delay, reducing unnecessary calls. It's useful for scenarios like search bars, where you want to avoid triggering an action on every keystroke.You can install the package using npm or yarn:
1npm install @d3vtool/hooks
1yarn add @d3vtool/hooks
useMState
useMState
is a custom mutable version of useState
hook for managing state in your React components. It can be used with a direct initial state value or with an initializer function for more complex state setups. It also supports updating state based on the most recent snapshot of the state in a mutable way.
1const [state, setState] = useMState(initialState);
initialState
: Can be a direct initial value or a function that returns the initial value.1const [count, setCount] = useMState(0);
1import { useMState } from "@d3vtool/hooks"; 2const [user, setUser] = useMState(() => ({ name: 'John', age: 30 })); 3 4// Updating state based on previous state: 5setUser(mostRecentSnapshot => { 6 mostRecentSnapshot.age += 1; 7}); 8 9// It also accepts a second argument for deep cloning the `mostRecentSnapshot` of the state. 10// By default, this is set to false, so it creates a shallow copy of `Object` types. 11setUser(mostRecentSnapshot => { 12 mostRecentSnapshot.age += 5; 13}, true);
1import { useMState } from "@d3vtool/hooks"; 2const [fruits, setFruits] = useMState([]); 3 4// Updating array state by mutating: 5setUser(prevFruits => { 6 prevFruits.push('Banana'); 7 prevFruits.push('Apple'); 8});
useBoolean
useBoolean
is a custom hook that provides an easy way to manage boolean states. It allows you to toggle the boolean state, set it to true
, or set it to false
.
1const [state, actions] = useBoolean(initialValue: boolean);
initialValue
: The initial value of the boolean state.1const [state, actions] = useBoolean(false);
This initializes the state to false
.
1const [state, actions] = useBoolean(false); 2 3return ( 4 <div> 5 <p>The current state is: {state ? 'True' : 'False'}</p> 6 <button onClick={actions.toggle}>Toggle State</button> 7 </div> 8);
true
or false
:1const [state, actions] = useBoolean(false); 2 3return ( 4 <div> 5 <button onClick={actions.setTrue}>Set to True</button> 6 <button onClick={actions.setFalse}>Set to False</button> 7 </div> 8);
toggle
: Flips the current state between true
and false
.setTrue
: Sets the state to true
.setFalse
: Sets the state to false
.useClickOutside
useClickOutside
is a custom hook that triggers a callback when a click event occurs outside the referenced element. It allows you to detect clicks outside a specific component and can be useful for scenarios like closing modals or dropdowns.
1const ref = useClickOutside(action: VoidFunction);
action
: The function to be triggered when a click occurs outside the referenced element.1import { useClickOutside } from "@d3vtool/hooks"; 2 3const DropdownComponent: React.FC = () => { 4 5 const dropdownRef = useClickOutside(() => { 6 console.log("Clicked outside the dropdown"); 7 }); 8 9 return ( 10 <div> 11 <div ref={dropdownRef} style={{ padding: "20px", backgroundColor: "lightblue" }}> 12 <p>Dropdown content</p> 13 <button>Click me</button> 14 </div> 15 <p>Click outside the box to trigger the action.</p> 16 </div> 17 ); 18}; 19 20export default DropdownComponent;
usePersistentState
usePersistentState
is a custom hook that manages state and persists it in localStorage
. It allows you to store and retrieve state values across sessions and tabs, with optional features like clearing the state when the component unmounts, delayed saving, useLayout
ensures the state is synchronized and fetched from storage immediately during the layout phase when the component is rendered for the first time and custom serialization and deserialization function for user-defined type.
Primitive Types: e.g. numbers
, strings
, booleans
.
Object Types: e.g. plain objects
and arrays
.
Special Object Types:
Map
, Set
, Date
, BigInt
, RegExp
.User-defined Types: You can provide custom serialization and deserialization functions within config for complex types like classes or non-JSON-serializable objects.
Persistent State Across Tabs: Synchronize state across multiple browser windows or tabs in real-time.
Optimized Caching: Once a state is fetched from localStorage
, it is cached for improved performance on subsequent reads.
Efficient State Updates: Delayed saving of state reduces unnecessary writes to localStorage
, which can improve performance when state changes rapidly.
saveDelay
: Optional delay before saving the state to localStorage
, useful for debouncing frequent state changes.
Automatic Cleanup: Option to automatically clear state from localStorage
when the component unmounts using the clearStorageOnUnMount
option.
Real-time Synchronization: State updates are synchronized across all components and tabs in real-time when using the same key.
Custom Serialization and Deserialization: Provides flexibility to serialize and deserialize complex objects through custom functions.
Reduced Re-renders: Internal caching reduces re-renders by avoiding unnecessary reads from localStorage
.
Cross-tab synchronization: Ideal for state that needs to be consistent across multiple tabs or windows.
Form auto-save: Keep form data persistent across sessions or tabs.
Optimizing performance: Reduce frequent reads and writes to localStorage
to enhance app performance.
1const [state, setState] = usePersistentState<T>( 2 key: string, 3 initialState: T | () => T, 4 config?: { 5 saveDelay?: number, 6 clearStorageOnUnMount?: boolean, 7 useLayout?: boolean, 8 serialize?: SerializerFn<T>, 9 deserialize?: DeSerializerFn<T> 10 } 11);
key
: A unique identifier for the stored state in localStorage
.
initialState
: The initial state value or a function that returns the initial state.
config
: Optional configuration object:
saveDelay
: (Default: 300ms
) The delay before saving the state to localStorage
after a state update. Useful for debouncing rapid state changes.
clearStorageOnUnMount
: (Default: false
) Boolean flag indicating whether to clear the state from localStorage
when the component unmounts.
useLayout
: (Default: false
) If true
, synchronizes state ( uses useLayoutEffect ) updates during the layout phase to immediately reflect updates in the UI.
serialize
: (Optional) Custom serialization function that converts state to a string before saving it to localStorage
.
deserialize
: (Optional) Custom deserialization function that parses the string from localStorage
back into the original state.
1import { usePersistentState } from "@d3vtool/hooks"; 2 3const CounterComponent: React.FC = () => { 4 const [count, setCount] = usePersistentState("count", 0); 5 6 function handleIncrement() { 7 setCount(prev => prev + 1); 8 } 9 10 function handleDecrement() { 11 setCount(prev => prev - 1); 12 } 13 14 return ( 15 <div style={{ 16 display: "flex", 17 alignItems: "center", 18 justifyContent: "center", 19 gap: "12px", 20 marginTop: "12rem" 21 }}> 22 <button onClick={handleDecrement}>DEC</button> 23 <p>{count}</p> 24 <button onClick={handleIncrement}>INC</button> 25 </div> 26 ); 27}; 28 29export default CounterComponent;
clearStorageOnUnMount
and saveDelay
1import { usePersistentState } from "@d3vtool/hooks"; 2 3// Define config outside or use useMemo to prevent re-creation on every render. 4const pStateConfig = { 5 saveDelay: 200, // Save after 200ms delay 6 clearStorageOnUnMount: true 7} 8 9const SessionComponent: React.FC = () => { 10 const [sessionData, setSessionData] = usePersistentState('session', {}, pStateConfig); 11 12 return ( 13 <div> 14 <p>Session Data: {JSON.stringify(sessionData)}</p> 15 <button onClick={() => setSessionData({ user: 'John Doe' })}>Set User</button> 16 <button onClick={() => setSessionData({})}>Clear Session</button> 17 </div> 18 ); 19}; 20 21export default SessionComponent;
useLayout
Option1import { usePersistentState } from "@d3vtool/hooks"; 2 3const LayoutComponent: React.FC = () => { 4 const [layoutData, setLayoutData] = usePersistentState('layoutData', { theme: 'light' }, { 5 useLayout: true 6 }); 7 8 return ( 9 <div> 10 <p>Layout Data: {JSON.stringify(layoutData)}</p> 11 <button onClick={() => setLayoutData({ theme: 'dark' })}>Change Theme</button> 12 </div> 13 ); 14}; 15 16export default LayoutComponent;
serialize
and deserialize
Functions1import React from 'react'; 2import { usePersistentState } from "@d3vtool/hooks"; 3 4class Product { 5 public static selfInstance: Product | null = null; 6 7 constructor(name: string, price: number) { 8 this.name = name; 9 this.price = price; 10 } 11 12 static serialize(product: Product): string { 13 return `${product.name},${product.price}`; 14 } 15 16 static deserialize(serialized: string): Product { 17 const [name, price] = serialized.split(','); 18 return new Product(name, parseFloat(price)); 19 } 20 21 static create(name: string, price: number): Product { 22 if (Product.selfInstance === null) { 23 Product.selfInstance = new Product(name, price); 24 } else { 25 Product.selfInstance.name = name; 26 Product.selfInstance.price = price; 27 } 28 return Product.selfInstance; 29 } 30} 31// Or you can define this `config` inside your component 32// with useMemo hook in order to avoid re-creation on every re-render 33const config = { 34 serialize: Product.serialize, 35 deserialize: Product.deserialize 36} 37 38const ProductComponent: React.FC = () => { 39 40 // Initializing product using the create method to ensure the singleton pattern 41 const [product, setProduct] = usePersistentState("product", Product.create("Laptop", 1200), config); 42 43 function updatePrice() { 44 setProduct(Product.create("Laptop", 1500)); // Update price of the product 45 } 46 47 return ( 48 <div> 49 <p>Product: {product.name}, Price: ${product.price}</p> 50 <button onClick={updatePrice}>Update Price</button> 51 </div> 52 ); 53}; 54 55export default ProductComponent;
Save Delay: The saveDelay
option allows you to debounce rapid state updates before saving to localStorage
. This reduces unnecessary writes when the state is changing frequently, such as in form inputs.
Clear on Unmount: Use clearStorageOnUnMount
to remove the stored state when the component unmounts, which is helpful for preventing stale data from persisting across sessions.
Real-Time Syncing: The state is automatically synced across all tabs and windows, providing real-time synchronization, which is ideal for managing state in applications with multiple browser tabs or windows.
useReadPersistentState
useReadPersistentState
is a custom hook that reads the persistent state from localStorage
without providing the ability to update it across windows or tabs. This hook supports deserializing the state value from localStorage
using an optional custom deserialization function.
1const state = useReadPersistentState<T>( 2 key: string, 3 deserializerFn?: DeSerializerFn<T> 4): T | undefined;
key
: A unique string to identify the stored state in localStorage
.
deserializerFn
: (Optional) A custom function to deserialize the state value from localStorage
. Defaults to a generic deserialize
function.
Returns: The deserialized state value if found in storage, or undefined
if no value is found for the given key.
1import { useReadPersistentState } from "@d3vtool/hooks"; 2 3const ReadCounterComponent: React.FC = () => { 4 const counter = useReadPersistentState<number>("counter"); 5 6 return ( 7 <div> 8 Read Counter: {counter} 9 </div> 10 ); 11}; 12 13export default ReadCounterComponent;
1import { useReadPersistentState } from "@d3vtool/hooks"; 2 3const ReadCounterComponent: React.FC = () => { 4 const counter = useReadPersistentState<BigInt>("counter"); 5 6 return ( 7 <div> 8 Read Counter: {counter} 9 </div> 10 ); 11}; 12 13export default ReadCounterComponent;
1class User { 2 constructor(public name: string) { 3 this.name = name; 4 } 5 6 static serializerFn(user: User): string { 7 return user.name; 8 } 9 10 static deserializerFn(data: string): User { 11 return new User(data); 12 } 13}
1import User from "./User.ts"; 2 3const ReadUserComponent: React.FC = () => { 4 const userState = useReadPersistentState<User>('user', User.deserializerFn); 5 6 return ( 7 <div> 8 User: {userState?.name} 9 </div> 10 ); 11}; 12 13export default ReadUserComponent;
useReadPersistentState
allows reading data from localStorage
but does not allow updating the state across windows or tabs.
Custom deserialization functions are helpful when dealing with unsupported types in localStorage
, such as custom classes or non json-serializable object.
If no deserialization function is passed, a default deserialization is applied to parse the stored value.
createHub
creates a shared state hub that can manage and synchronize state across multiple components.
1const myHub = createHub<T>(initialState: T | InitializerAction<T>);
initialState
: The initial state value or a function that returns the initial state.1import { createHub } from "@d3vtool/hooks"; 2 3const myHub = createHub({ count: 0 });
createComputedHub
creates a new computed hub that derives its state from an existing hub using a compute action.
1const computedHub = createComputedHub<T>(hub: Hub<T>, computeAction: ComputeAction<T>);
hub
: The original hub from which the state will be derived.computeAction
: A function that computes the new state based on the current state of the original hub.1import { createHub, createComputedHub } from "@d3vtool/hooks"; 2 3const countHub = createHub({ count: 0 }); 4 5// Create a computed hub that doubles the count value: 6// Always use `createComputedHub` with `useReadHub` 7const doubleComputedHub = createComputedHub(countHub, (state) => ({ 8 count: state.count * 2 9})); 10 11 12export function DoubleCounter() { 13 14 // Always use computedHub with `useReadHub` 15 // Whenever 'countHub' is updated, 'doubleComputedHub' will automatically update as well. 16 const doubleCount = useReadHub<number>(doubleComputedHub); 17 18 return ( 19 <> 20 <p>{doubleCount}</p> 21 </> 22 ) 23}
useHub
is a custom hook that subscribes to a shared state hub and provides access to the current state along with a function to update it.
1const [state, setState] = useHub<T>(hub: Hub<T>);
hub
: The shared state hub that holds the state.1import { useHub } from "@d3vtool/hooks"; 2 3// Always create `hub` outside of your component. 4const myHub = createHub({ count: 0 }); 5 6const CounterComponent: React.FC = () => { 7 const [count, setCount] = useHub(myHub); 8 9 return ( 10 <div> 11 <p>Count: {count}</p> 12 <button onClick={() => setCount(prev => prev + 1)}>Increment</button> 13 <button onClick={() => setCount(0)}>Reset</button> 14 </div> 15 ); 16}; 17 18export default CounterComponent;
useReadHub
is a custom hook that reads the current state from a shared state hub without providing a way to update it.
1const state = useReadHub<T>(hub: Hub<T>);
hub
: The shared state hub that holds the state.1import { useReadHub } from "@d3vtool/hooks"; 2 3const DisplayCounterComponent: React.FC = () => { 4 const count = useReadHub<number>(myHub); 5 6 return ( 7 <div> 8 <p>Count: {count}</p> 9 </div> 10 ); 11}; 12 13export default DisplayCounterComponent;
useComputeHub
is a custom hook that computes a derived state from a shared state hub using a provided compute action.
1const computedState = useComputeHub<T>(hub: Hub<T>, computeAction: ComputeAction<T>);
hub
: The shared state hub that holds the state.computeAction
: A function that computes a derived state based on the current state of the hub.1import { useComputeHub } from "@d3vtool/hooks"; 2 3// Always create `hub` outside of your component. 4const myHub = createHub({ count: 0 }); 5 6const ComputedCounterComponent: React.FC = () => { 7 const doubleCount = useComputeHub(myHub, (state) => state.count * 2); 8 9 return ( 10 <div> 11 <p>Double Count: {doubleCount}</p> 12 </div> 13 ); 14}; 15 16export default ComputedCounterComponent;
useStoredHub
is a custom hook that synchronizes a shared state hub with persistent storage (like localStorage). This allows the state of the hub to persist across pages and tabs reloads or navigation.
1const [state, setState] = useStoredHub<T>(key: string, hub: Hub<T>);
key
: The key used to store and retrieve the hub's state from persistent storage (e.g., localStorage).hub
: The shared state hub that holds the state.This example demonstrates how to use useStoredHub
to manage and synchronize a counter across different pages across tabs. The counter state persists using localStorage and is shared between the Home
and ContactUs
components.
1import { createHub } from "@d3vtool/hooks"; 2 3export const countHub = createHub(1);
1import { countHub } from "./countHub"; 2import { Link } from "react-router-dom"; 3import { useStoredHub } from "@d3vtool/hooks"; 4 5export default function Page1() { 6 7 const [count, setCount] = useStoredHub<number>("counter", countHub); 8 9 function handleInc() { 10 setCount(prev => prev + 1); 11 } 12 13 function handleDec() { 14 setCount(prev => prev - 1); 15 } 16 17 return ( 18 <div style={{ 19 display: "flex", 20 alignItems: "center", 21 justifyContent: "center", 22 gap: "12px", 23 marginTop: "12rem" 24 }}> 25 <button onClick={handleDec}>DEC</button> 26 <p>{count}</p> 27 <button onClick={handleInc}>INC</button> 28 <Link to="/page2">Page 2</Link> 29 </div> 30 ); 31}
1import { countHub } from "./countHub"; 2import { Link } from "react-router-dom"; 3import { useStoredHub } from "@d3vtool/hooks"; 4 5export default function Page2() { 6 7 const [count, setCount] = useStoredHub<number>("counter", countHub); 8 9 function handleInc() { 10 setCount(prev => prev + 1); 11 } 12 13 function handleDec() { 14 setCount(prev => prev - 1); 15 } 16 17 return ( 18 <div style={{ 19 display: "flex", 20 alignItems: "center", 21 justifyContent: "center", 22 gap: "12px", 23 marginTop: "12rem" 24 }}> 25 <button onClick={handleDec}>DEC</button> 26 <p>{count}</p> 27 <button onClick={handleInc}>INC</button> 28 <Link to="/">Page 1</Link> 29 </div> 30 ); 31}
useStoredHub
is used in both Page1
and Page2
components with the same key "counter"
, ensuring that the counter value is shared and synchronized between the two pages or across tabs.counter
state is persisted using localStorage and can be incremented or decremented on either page. The updated state is reflected on both pages or in pages opend on different tabs.createPromiseHub
createPromiseHub
is a function that creates a hub to manage state with a promise action. This hub can then be used with the usePromiseHub
or usePromiseReadHub
hooks.
1const promiseHub = createPromiseHub(initialState, promiseAction);
initialState
: The initial state value or initializer function.promiseAction
: The async function that will resolve to update the state.1import { createPromiseHub } from "@d3vtool/hooks"; 2 3export const fetchUserDataHub = createPromiseHub(undefined, async (prevState) => { 4 const response = await fetch('/api/user'); 5 const data = await response.json(); 6 return data; 7});
usePromiseHub
usePromiseHub
is a custom hook that helps manage asynchronous state using a promise hub. It provides the current state, loading status, error information, and a way to re-trigger the async action. The hook can be configured to either trigger the promise immediately or allow manual re-triggering, and optionally integrate with React Suspense.
1const { data, error, isPending, reAction } = usePromiseHub(promiseHub, config?);
promiseHub
: The promise hub created using createPromiseHub
.config
: (Optional) Configuration object for the hook. It includes:
immediate
: If true
, the promise action will be triggered immediately on hook initialization. Defaults to true
.suspense
: If true
, the hook will integrate with React Suspense, suspending the component until the promise resolves. Defaults to false
.1import { usePromiseHub } from "@d3vtool/hooks"; 2import { fetchUserDataHub } from "./userHub"; 3 4const UserProfile: React.FC = () => { 5 const { data, error, isPending, reAction } = usePromiseHub(fetchUserDataHub); 6 7 return ( 8 <div> 9 {isPending ? <p>Loading user data...</p> : <p>User: {data?.name}</p>} 10 {error && <p>Error: {error.message}</p>} 11 <button onClick={reAction} disabled={isPending}>Retry</button> 12 </div> 13 ); 14}; 15 16export default UserProfile;
If you're using suspense
, you don't need to use the isPending
state, as React Suspense will handle the loading state for you.
1import { useMemo } from "react"; 2import { usePromiseHub } from "@d3vtool/hooks"; 3import { fetchUserDataHub } from "./userHub"; 4 5const UserProfile: React.FC = () => { 6 const config = useMemo(() => ({ suspense: true }), []); // Use useMemo to avoid recreating config on re-renders 7 const { data, error } = usePromiseHub(fetchUserDataHub, config); 8 9 return ( 10 {error && <p>Error: {error.message}</p>} 11 <p>User: {data?.name}</p> 12 ); 13}; 14 15export default UserProfile;
1import { Suspense } from "react"; 2import UserProfile from "./UserProfile"; 3 4const App: React.FC = () => { 5 6 return ( 7 <Suspense fallback={<p>Loading...</p>}> 8 <UserProfile /> 9 </Suspense> 10 ); 11}; 12 13export default App;
usePromiseReadHub
usePromiseReadHub
is a custom hook that provides read-only access to the state managed by a promise hub. It returns the current state, any error, and the loading status.
1const { data, error, isPending } = usePromiseReadHub(promiseHub);
promiseHub
: The promise hub managing the async state.suspense
: (Optional) If true
, integrates with React Suspense, suspending the component until the promise resolves.1import { usePromiseReadHub } from "@d3vtool/hooks"; 2import { fetchUserDataHub } from "./userHub"; 3 4const UserProfileReadOnly: React.FC = () => { 5 const { data, error, isPending } = usePromiseReadHub(fetchUserDataHub); 6 7 return ( 8 <div> 9 {isPending ? <p>Loading user data...</p> : <p>User: {data?.name}</p>} 10 {error && <p>Error: {error.message}</p>} 11 </div> 12 ); 13}; 14 15export default UserProfileReadOnly;
If you prefer to use React Suspense to handle the loading state automatically, you can enable it by passing true
for the suspense
flag.
1import { usePromiseReadHub } from "@d3vtool/hooks"; 2import { fetchUserDataHub } from "./userHub"; 3 4const UserProfileSuspense: React.FC = () => { 5 const { data, error } = usePromiseReadHub(fetchUserDataHub, true); 6 7 return ( 8 <p>User: {data?.name}</p> 9 {error && <p>Error: {error.message}</p>} 10 ); 11}; 12 13export default UserProfileSuspense;
1import { Suspense } from "react"; 2import UserProfileSuspense from "./UserProfileSuspense"; 3 4const App: React.FC = () => { 5 6 return ( 7 <Suspense fallback={<p>Loading...</p>}> 8 <UserProfileSuspense /> 9 </Suspense> 10 ); 11}; 12 13export default App;
suspense
is set to true
, it will automatically suspend the component's rendering until the promise resolves, showing the fallback (<p>Loading...</p>
) while loading.error
.usePromiseHubAction
usePromiseHubAction
is a custom hook that allows you to manually trigger an asynchronous action within a PromiseHub
from any other component and provides the current loading state and any errors.
1const { reAction, error, isPending } = usePromiseHubAction(promiseHub, suspense?);
reAction
: A function to trigger the asynchronous action manually.error
: The current error state if the action fails.isPending
: A boolean indicating whether the action is currently loading.suspense
: (Optional) If true
, the hook will suspend rendering until the promise is resolved.productListHub
The productListHub
is created using createPromiseHub
. It manages the asynchronous fetching of the product list from a REST API and stores the fetched data.
1import { createPromiseHub } from "@d3vtool/hooks"; 2import { TResponse, IProduct } from "./types"; // Assume you have these types 3 4export const productListHub = createPromiseHub<IProduct[] | undefined>(undefined, async () => { 5 const response = await fetch('http://localhost:4000/products'); 6 const data = await response.json(); 7 8 return data; 9});
1import { usePromiseHubAction } from "@d3vtool/hooks"; 2import { productListHub } from "./productListHub"; 3 4const ProductList: React.FC = () => { 5 const { reAction: refetchProducts, error, isPending } = usePromiseHubAction(productListHub); 6 7 return ( 8 <div> 9 <button onClick={refetchProducts} disabled={isPending}> 10 {isPending ? 'Loading...' : 'Refetch Products'} 11 </button> 12 {error && <p style={{ color: 'red' }}>Error fetching products: {error.message}</p>} 13 </div> 14 ); 15}; 16 17export default ProductList;
1import { productListHub } from "./productListHub"; 2import { usePromiseHubAction } from "@d3vtool/hooks"; 3 4const ProductList: React.FC = () => { 5 const { reAction: refetchProducts, error } = usePromiseHubAction(productListHub, true); 6 7 return ( 8 <div> 9 <button onClick={refetchProducts}> 10 Refetch Products 11 </button> 12 {error && <p style={{ color: 'red' }}>Error fetching products: {error.message}</p>} 13 </div> 14 ); 15}; 16 17export default ProductList;
1import { Suspense } from "react"; 2import ProductList from "./ProductList"; 3 4const App: React.FC = () => { 5 6 return ( 7 <Suspense fallback={<p>Loading Products...</p>}> 8 <ProductList /> 9 </Suspense> 10 ); 11}; 12 13export default App;
refetchProducts
action, which re-fetches the product list.Suspense
boundary, which will suspend rendering until the promise is resolved.fallback
prop is used to show a loading message while the promise is pending.suspense
flag is set to true
, the component suspends until the asynchronous action completes.useSecId
useSecId
is a custom hook that returns a function to generate unique string identifiers with customizable length and character set.
1const generateId = useSecId(length?: number, alphabets?: string);
length
(optional): The desired length of the generated ID. Defaults to 8
.alphabets
(optional): A string representing the set of characters to use when generating the ID.1import React from 'react'; 2import { useSecId } from "@d3vtool/hooks"; 3 4const IdGeneratorComponent: React.FC = () => { 5 const generateId = useSecId(); // Default: 8-character ID generator 6 const generateCustomId = useSecId(10, "ABC123"); // Custom: 10-character ID generator using "ABC123" 7 8 return ( 9 <div> 10 <p>Generated ID: {generateId()}</p> 11 <p>Custom Generated ID: {generateCustomId()}</p> 12 </div> 13 ); 14}; 15 16export default IdGeneratorComponent;
In this example, useSecId
is used to create two generators:
"ABC123"
.useForm
useForm
is a custom React hook for managing form state, handling validation, and submitting forms with asynchronous logic. It provides an efficient way to bind form inputs to a schema, track validation errors, and perform custom submission actions. A notable feature is that it minimizes unnecessary re-renders: the component will only re-render when a validation error occurs, not when the input changes, improving performance.
1const { 2 formData, 3 onSubmit, 4 formErrors, 5 listeners, 6 setFormData, 7 getFormData, 8 resetFields 9} = useForm<FormSchema>(initialFormData);
formData
: The current form state object containing the values of the form fields, where each key matches a field from the form schema.onSubmit
: A function to handle form submission. It supports middleware logic and triggers the submission process while handling form validation.formErrors
: An object representing error messages for each form field, mapping field names to error strings.listeners
: Event listeners to be spread onto form inputs. These include handlers such as onChange
and onBlur
, as well as a ref
action to set input references.setFormData
: A function to update the value of a specific form field. You can optionally hide error messages while setting data.getFormData
: A function to retrieve the value of a specific form field from the form data.resetFields
: A function that allows resetting all form fields. You can optionally hide error messages during the reset process.1import { useForm } from "@d3vtool/hooks"; 2import { Validator, VInfer, StringUtils } from "@d3vtool/utils";
useForm
: The main hook from the @d3vtool/hooks
package that handles form state, validation, and submission.Validator
: A utility from @d3vtool/utils
for defining form validation rules.VInfer
: A TypeScript helper to infer the type from a validation schema.StringUtils
: A utility for manipulating strings, like transforming keys into a readable format (used later for field placeholders).1const schema = Validator.object({
2 email: Validator.string().email(),
3 password: Validator.string().password(),
4});
5
6type SchemaType = typeof schema;
7type FormSchema = VInfer<SchemaType>;
schema
: Defines the validation rules for the form using the Validator.object
method. It includes:
email
: Must be a valid email string.password
: Must follow password rules (defined by Validator.string().password()
).SchemaType
: A TypeScript type generated from the schema
, allowing us to infer the shape of the form data.1/** 2 * Alternatively, you can define it directly within the hook argument. 3 * This way, there's no need to use `VInfer` as it will automatically 4 * infer the type. 5*/ 6const initialFormData: FormSchema = { 7 email: "", 8 password: "", 9};
initialFormData
: Provides the initial state for the form fields (both email
and password
are empty strings by default). This state is tied to the schema using VInfer
to ensure type safety.useForm
Hook in the Component1const { 2 formData, onSubmit, 3 formErrors, listeners 4} = useForm<SchemaType>(initialFormData, schema);
formData
: Holds the current values of the form fields (email
and password
).onSubmit
: Handles form submission logic and triggers validation.formErrors
: Contains validation error messages for form fields, if any exist.listeners
: An object that contains event listeners for input elements (e.g., onChange
, onBlur
, etc.).1async function handleOnSubmit() { 2 // Handle form submission logic (e.g., send data to the server) 3 console.log(formData); 4}
handleOnSubmit
: This function is called when the form is submitted. It logs the current form data but can be modified to perform any necessary actions like sending data to a server.1<main style={{ height: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: '2.5rem', marginTop: '3rem' }}> 2 <h1>Login</h1> 3 <form 4 style={{ width: '300px', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: '0.75rem' }} 5 onSubmit={onSubmit(handleOnSubmit)} 6 >
onSubmit
: When the form is submitted, onSubmit
is called, triggering the validation and then it will callback the submission logic.1{ 2 Object.keys(formData).map((key) => ( 3 <div key={key} style={{ width: '100%' }}> 4 <input 5 name={key} // `name` should be the same as `schema key` 6 placeholder={StringUtils.toTitleCase(key)} 7 type={key.includes('password') ? 'password' : 'text'} 8 {...listeners} // Spread the input listeners here 9 style={{ width: '100%', fontSize: '1rem', padding: '0.4rem' }} 10 /> 11 { 12 formErrors[key as keyof typeof formErrors] && ( 13 <span style={{ color: 'crimson' }}> 14 {formErrors[key as keyof typeof formErrors]} 15 </span> 16 ) 17 } 18 </div> 19 )) 20}
email
and password
) are rendered dynamically using Object.keys(formData)
. For each field:
input
field is created with the proper name and placeholder.password
, the input
type is set to "password"
, otherwise, it's a text field.listeners
: The event listeners for each input are spread dynamically from {...listeners}
.1<button 2 type="submit" 3 title="Login" 4 style={{ cursor: 'pointer', padding: '0.5rem 0', marginTop: '0.5rem', fontSize: '1rem', width: '100%' }} 5> 6 Login 7</button>
1const {
2 formData,
3 setFormData,
4} = useForm<FormSchema>(initialFormData);
5
6// Example 1: Update the 'email' field with a new value
7setFormData('email', 'user@example.com');
8
9// Example 2: Update the 'email' field and hide any associated error messages
10setFormData('email', 'user@example.com', true);
1const { 2 formData, 3 getFormData, 4} = useForm<FormSchema>(initialFormData); 5 6// Example 1: Retrieve the value of the 'email' field 7const emailValue = getFormData('email'); 8console.log(emailValue); // Outputs: user@example.com 9 10// Example 2: Retrieve the value of the 'password' field 11const passwordValue = getFormData('password'); 12console.log(passwordValue); // Outputs: ********
1const { 2 resetFields, 3} = useForm<FormSchema>(initialFormData); 4 5// Example 1: Reset all form fields and clear any error messages 6resetFields(); 7 8// Example 2: Reset all form fields but retain the current error messages 9resetFields(true);
onSubmit
function allows you to add any custom logic on form submission, making it highly flexible for various use cases like API requests or complex business logic.useDebounce
useDebounce
is a custom React hook that delays the execution of a provided function until after a specified delay time has passed since the last time the function was invoked. This is especially useful for scenarios like handling user input (e.g., search bar) where you want to avoid triggering an action on every keystroke.
1const debounce = useDebounce(delay: ms, debounceAction: DebounceAction): VoidFunction;
delay
: The debounce delay in milliseconds (ms
). This defines how long to wait after the last invocation before calling the debounceAction
.debounceAction
: The action or function that you want to debounce. It will only be executed after the specified delay period.1import React, { useCallback } from 'react'; 2import { useDebounce } from '@d3vtool/hooks'; 3 4export default function Search() { 5 6// Memoize the trigger function 7 const memoizedTrigger = useCallback(() => { 8 console.log("Searching..."); 9 // Your search logic here 10 }, []); 11 12 // Use the useDebounce hook to delay the trigger function 13 const debounce = useDebounce(800, memoizedTrigger); 14 15 return ( 16 <div> 17 <input 18 type="text" 19 placeholder="Search..." 20 onChange={debounce} // Debounced onChange handler 21 /> 22 </div> 23 ); 24}
useDebounce
?This package is open-source and licensed under the MIT License.
No vulnerabilities found.
No security vulnerabilities found.