Common utility functions and components specifically designed for React development.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Modern React hooks for state management, memoization, and lifecycle optimization with enhanced functionality beyond standard React hooks.
Hook for managing controlled/uncontrolled state patterns, commonly used in form components that can be either controlled or uncontrolled.
/**
* Hook for controlled/uncontrolled state management
* @param {T | (() => T)} defaultStateValue - Default state value or function
* @param {object} [option] - Configuration options
* @returns {[R, (value: T) => void]} State value and setter function
*/
function useControlledState<T, R = T>(
defaultStateValue: T | (() => T),
option?: {
/** Default value when component is uncontrolled */
defaultValue?: T | (() => T);
/** External value when component is controlled */
value?: T;
/** Callback when value changes */
onChange?: (value: T, prevValue: T) => void;
/** Transform state value before returning */
postState?: (value: T) => T;
}
): [R, (value: T) => void];Usage Examples:
import useControlledState from 'rc-util/lib/hooks/useMergedState';
// Basic controlled/uncontrolled input
function Input({ value, defaultValue, onChange }) {
const [inputValue, setInputValue] = useControlledState('', {
value,
defaultValue,
onChange
});
return (
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
);
}
// With post-processing
function NumberInput({ value, onChange }) {
const [numValue, setNumValue] = useControlledState(0, {
value,
onChange,
postState: (val) => Math.max(0, val) // Ensure non-negative
});
return (
<input
type="number"
value={numValue}
onChange={(e) => setNumValue(Number(e.target.value))}
/>
);
}
// Uncontrolled with default
<Input defaultValue="Hello" />
// Controlled
<Input value={inputValue} onChange={setInputValue} />Enhanced useEffect that passes previous dependencies to the callback, useful for comparison logic.
/**
* Enhanced useEffect that passes previous dependencies to callback
* @param {(prevDeps: any[]) => void} callback - Effect callback receiving previous deps
* @param {any[]} deps - Dependencies array
*/
function useEffect(
callback: (prevDeps: any[]) => void,
deps: any[]
): void;Usage Example:
import useEffect from 'rc-util/lib/hooks/useEffect';
function Component({ userId, filterType }) {
useEffect((prevDeps) => {
const [prevUserId, prevFilterType] = prevDeps;
// Only refetch if userId changed, not filterType
if (prevUserId !== userId) {
fetchUserData(userId);
}
// Only update filter if filterType changed
if (prevFilterType !== filterType) {
updateFilter(filterType);
}
}, [userId, filterType]);
}Custom memoization hook with custom comparison function for more control over when values are recalculated.
/**
* Custom memoization hook with custom comparison function
* @param {() => Value} getValue - Function to get the memoized value
* @param {Condition} condition - Current condition for comparison
* @param {(prev: Condition, next: Condition) => boolean} shouldUpdate - Comparison function
* @returns {Value} Memoized value
*/
function useMemo<Value, Condition = any[]>(
getValue: () => Value,
condition: Condition,
shouldUpdate: (prev: Condition, next: Condition) => boolean
): Value;Usage Examples:
import useMemo from 'rc-util/lib/hooks/useMemo';
// Deep comparison for objects
function ExpensiveComponent({ config }) {
const processedData = useMemo(
() => expensiveCalculation(config),
config,
(prev, next) => JSON.stringify(prev) !== JSON.stringify(next)
);
return <div>{processedData}</div>;
}
// Custom comparison for arrays
function ListComponent({ items, sortBy }) {
const sortedItems = useMemo(
() => [...items].sort((a, b) => a[sortBy] - b[sortBy]),
{ items, sortBy },
(prev, next) =>
prev.items.length !== next.items.length ||
prev.sortBy !== next.sortBy ||
prev.items.some((item, index) => item.id !== next.items[index]?.id)
);
return (
<ul>
{sortedItems.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
);
}React ref manipulation utilities for working with refs in complex scenarios.
/**
* Fill a ref with a node value
* @param {React.Ref<T>} ref - Ref to fill (function or object ref)
* @param {T} node - Node value to assign
*/
function fillRef<T>(ref: React.Ref<T>, node: T): void;
/**
* Merge multiple refs into one ref function
* @param {...React.Ref<T>[]} refs - Refs to merge
* @returns {React.Ref<T>} Combined ref function
*/
function composeRef<T>(...refs: React.Ref<T>[]): React.Ref<T>;
/**
* Check if a component supports refs
* @param {any} nodeOrComponent - React component or node
* @returns {boolean} True if component supports refs
*/
function supportRef(nodeOrComponent: any): boolean;Usage Examples:
import { fillRef, composeRef, supportRef } from 'rc-util/lib/ref';
// Compose multiple refs
function ForwardedComponent(props, ref) {
const internalRef = useRef();
const combinedRef = composeRef(ref, internalRef);
useEffect(() => {
// Use internal ref for component logic
if (internalRef.current) {
internalRef.current.focus();
}
}, []);
return <input ref={combinedRef} />;
}
// Check ref support before using
function ParentComponent({ children }) {
const childRef = useRef();
const enhancedChildren = React.Children.map(children, (child) => {
if (supportRef(child)) {
return React.cloneElement(child, { ref: childRef });
}
return child;
});
return <div>{enhancedChildren}</div>;
}
// Manual ref filling
function CustomRef() {
const handleRef = useCallback((node) => {
// Fill multiple refs manually
fillRef(externalRef, node);
fillRef(internalRef, node);
}, []);
return <div ref={handleRef} />;
}RequestAnimationFrame wrapper with fallback for server-side rendering and older browsers.
/**
* RequestAnimationFrame wrapper with fallback
* @param {() => void} callback - Function to call on next frame
* @returns {number} Request ID for cancellation
*/
function wrapperRaf(callback: () => void): number;
/**
* Cancel a requestAnimationFrame request
* @param {number} id - Request ID to cancel
*/
wrapperRaf.cancel: (id: number) => void;Usage Example:
import raf from 'rc-util/lib/raf';
// Schedule animation
const rafId = raf(() => {
// Animation code here
element.style.opacity = '1';
});
// Cancel if needed
raf.cancel(rafId);
// Use in custom hook
function useAnimationFrame(callback) {
const requestRef = useRef();
useEffect(() => {
const animate = () => {
callback();
requestRef.current = raf(animate);
};
requestRef.current = raf(animate);
return () => {
if (requestRef.current) {
raf.cancel(requestRef.current);
}
};
}, [callback]);
}Install with Tessl CLI
npx tessl i tessl/npm-rc-util