useHooks.iov4.1.2
DocsBlogGitHub
Hooks
No hooks found in any category.

useProxy

state

Installation

npx usehooks-cli@latest add use-proxy

Description

A React hook that creates and manages JavaScript Proxy objects, enabling you to intercept and customize operations performed on objects (such as property lookup, assignment, enumeration, function invocation, etc.). Perfect for creating reactive objects, validation, logging, or data transformation.

Parameters

NameTypeDefaultDescription
initialTargetT extends object-The initial target object to be proxied
handlerProxyHandler<T>-An object that defines which operations will be intercepted and how to redefine intercepted operations

Return Type

UseProxyReturn<T>
PropertyTypeDescription
proxyTThe proxy object that intercepts operations on the target
targetTThe original target object
updateTarget(newTarget: T | ((prevTarget: T) => T)) => voidFunction to update the target object
revoke() => voidFunction to revoke the proxy, making it unusable
isRevokedbooleanWhether the proxy has been revoked

Examples

Property Access Logging

Log all property access on an object

1const { proxy } = useProxy( 2 { name: 'John', age: 30 }, 3 { 4 get(target, prop) { 5 console.log(`Accessing property: ${String(prop)}`); 6 return target[prop]; 7 } 8 } 9); 10 11// Usage: proxy.name will log "Accessing property: name"

Property Validation

Validate property assignments

1const { proxy } = useProxy( 2 { age: 0 }, 3 { 4 set(target, prop, value) { 5 if (prop === 'age' && (typeof value !== 'number' || value < 0)) { 6 throw new Error('Age must be a positive number'); 7 } 8 target[prop] = value; 9 return true; 10 } 11 } 12); 13 14// proxy.age = -5; // Throws error

Default Values

Provide default values for undefined properties

1const { proxy } = useProxy( 2 {}, 3 { 4 get(target, prop) { 5 return prop in target ? target[prop] : 'default'; 6 } 7 } 8); 9 10// proxy.anyProperty returns 'default' if not set

Revocable Proxy

Create a proxy that can be revoked

1const { proxy, revoke, isRevoked } = useProxy( 2 { data: 'sensitive' }, 3 { 4 get(target, prop) { 5 console.log('Access granted'); 6 return target[prop]; 7 } 8 } 9); 10 11// Later revoke access 12revoke(); 13console.log(isRevoked); // true

Dependencies

react

Notes

  • The proxy is recreated when the target or handler changes
  • Once revoked, the proxy becomes unusable and operations will throw TypeError
  • The hook uses Proxy.revocable() to allow controlled revocation
  • All handler methods are optional - omitted traps forward to the target
  • Perfect for implementing reactive objects, validation, or debugging

Implementation

1"use client"; 2 3import { useState, useCallback, useMemo } from "react"; 4 5type ProxyHandler<T extends object> = { 6 get?: (target: T, property: string | symbol, receiver: any) => any; 7 set?: ( 8 target: T, 9 property: string | symbol, 10 value: any, 11 receiver: any 12 ) => boolean; 13 has?: (target: T, property: string | symbol) => boolean; 14 deleteProperty?: (target: T, property: string | symbol) => boolean; 15 ownKeys?: (target: T) => ArrayLike<string | symbol>; 16 getOwnPropertyDescriptor?: ( 17 target: T, 18 property: string | symbol 19 ) => PropertyDescriptor | undefined; 20 defineProperty?: ( 21 target: T, 22 property: string | symbol, 23 attributes: PropertyDescriptor 24 ) => boolean; 25 preventExtensions?: (target: T) => boolean; 26 getPrototypeOf?: (target: T) => object | null; 27 isExtensible?: (target: T) => boolean; 28 setPrototypeOf?: (target: T, prototype: object | null) => boolean; 29 apply?: (target: T, thisArg: any, argArray: any[]) => any; 30 construct?: (target: T, argArray: any[], newTarget: Function) => object; 31}; 32 33interface UseProxyReturn<T extends object> { 34 proxy: T; 35 target: T; 36 updateTarget: (newTarget: T | ((prevTarget: T) => T)) => void; 37 revoke: () => void; 38 isRevoked: boolean; 39} 40 41export function useProxy<T extends object>( 42 initialTarget: T, 43 handler: ProxyHandler<T> 44): UseProxyReturn<T> { 45 const [target, setTarget] = useState<T>(initialTarget); 46 const [isRevoked, setIsRevoked] = useState(false); 47 48 // Create a revocable proxy 49 const { proxy, revoke: revokeProxy } = useMemo(() => { 50 if (isRevoked) { 51 return { proxy: target, revoke: () => {} }; 52 } 53 return Proxy.revocable(target, handler); 54 }, [target, handler, isRevoked]); 55 56 const updateTarget = useCallback( 57 (newTarget: T | ((prevTarget: T) => T)) => { 58 if (isRevoked) { 59 console.warn("Cannot update target of a revoked proxy"); 60 return; 61 } 62 setTarget((prevTarget) => 63 typeof newTarget === "function" 64 ? (newTarget as (prevTarget: T) => T)(prevTarget) 65 : newTarget 66 ); 67 }, 68 [isRevoked] 69 ); 70 71 const revoke = useCallback(() => { 72 if (!isRevoked) { 73 revokeProxy(); 74 setIsRevoked(true); 75 } 76 }, [revokeProxy, isRevoked]); 77 78 return { 79 proxy: isRevoked ? target : proxy, 80 target, 81 updateTarget, 82 revoke, 83 isRevoked, 84 }; 85} 86