A comprehensive collection of 75+ React hooks for state and UI management including storage, events, browser APIs, and performance optimizations
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Observer-based hooks for intersection detection, resize monitoring, mutation tracking, and viewport visibility using modern browser Observer APIs.
Intersection Observer API integration for detecting when elements enter/leave the viewport.
/**
* Intersection Observer API integration
* @param options - IntersectionObserver configuration options
* @returns Object with ref callback and intersection entry
*/
function useIntersection<T extends HTMLElement = any>(
options?: IntersectionObserverInit
): UseIntersectionReturnValue<T>;
interface UseIntersectionReturnValue<T> {
ref: React.RefCallback<T | null>;
entry: IntersectionObserverEntry | null;
}Usage Examples:
import { useIntersection } from "@mantine/hooks";
// Basic intersection detection
function LazyImage({ src, alt }: { src: string; alt: string }) {
const { ref, entry } = useIntersection({
threshold: 0.1,
});
const isVisible = entry?.isIntersecting;
return (
<div ref={ref}>
{isVisible ? (
<img src={src} alt={alt} />
) : (
<div style={{ height: '200px', background: '#f0f0f0' }}>
Loading...
</div>
)}
</div>
);
}
// Infinite scrolling
function InfiniteList({ items, onLoadMore }: Props) {
const { ref, entry } = useIntersection({
threshold: 1.0,
});
useEffect(() => {
if (entry?.isIntersecting) {
onLoadMore();
}
}, [entry?.isIntersecting, onLoadMore]);
return (
<div>
{items.map(item => <Item key={item.id} {...item} />)}
<div ref={ref}>Loading more...</div>
</div>
);
}Resize Observer API for monitoring element size changes.
/**
* Resize Observer API for element size monitoring
* @param callback - Function called when element resizes
* @returns Ref callback to attach to target element
*/
function useResizeObserver<T extends HTMLElement = any>(
callback: (entries: ResizeObserverEntry[], observer: ResizeObserver) => void
): React.RefCallback<T | null>;Usage Examples:
import { useResizeObserver } from "@mantine/hooks";
function ResponsiveComponent() {
const [size, setSize] = useState({ width: 0, height: 0 });
const ref = useResizeObserver<HTMLDivElement>((entries) => {
const entry = entries[0];
if (entry) {
setSize({
width: entry.contentRect.width,
height: entry.contentRect.height,
});
}
});
return (
<div ref={ref} style={{ resize: 'both', overflow: 'auto', border: '1px solid' }}>
<p>Size: {size.width} × {size.height}</p>
<p>Resize me!</p>
</div>
);
}Convenience hook for tracking element dimensions.
/**
* Track element dimensions
* @returns Object with ref, width, and height
*/
function useElementSize<T extends HTMLElement = any>(): {
ref: React.RefCallback<T | null>;
width: number;
height: number;
};Usage Examples:
import { useElementSize } from "@mantine/hooks";
function SizeAwareComponent() {
const { ref, width, height } = useElementSize();
return (
<div ref={ref}>
<p>Element size: {width} × {height}</p>
{width < 300 && <div>Mobile layout</div>}
{width >= 300 && width < 768 && <div>Tablet layout</div>}
{width >= 768 && <div>Desktop layout</div>}
</div>
);
}Mutation Observer API for monitoring DOM changes.
/**
* Mutation Observer API for DOM change monitoring
* @param callback - Function called when mutations occur
* @param options - MutationObserver configuration options
* @returns Ref callback to attach to target element
*/
function useMutationObserver<T extends HTMLElement = any>(
callback: MutationCallback,
options?: MutationObserverInit
): React.RefCallback<T | null>;Usage Examples:
import { useMutationObserver } from "@mantine/hooks";
function DynamicContentWatcher() {
const [changeCount, setChangeCount] = useState(0);
const ref = useMutationObserver<HTMLDivElement>(
(mutations) => {
setChangeCount(prev => prev + mutations.length);
},
{
childList: true,
subtree: true,
attributes: true,
characterData: true,
}
);
const addContent = () => {
const element = ref.current;
if (element) {
const newElement = document.createElement('p');
newElement.textContent = `Added at ${new Date().toLocaleTimeString()}`;
element.appendChild(newElement);
}
};
return (
<div>
<button onClick={addContent}>Add Content</button>
<p>Changes detected: {changeCount}</p>
<div ref={ref}>
<p>Original content</p>
</div>
</div>
);
}Simple viewport visibility detection.
/**
* Simple viewport visibility detection
* @param options - IntersectionObserver options
* @returns Object with ref and visibility state
*/
function useInViewport<T extends HTMLElement = any>(
options?: IntersectionObserverInit
): UseInViewportReturnValue<T>;
interface UseInViewportReturnValue<T extends HTMLElement = any> {
ref: React.RefCallback<T | null>;
inViewport: boolean;
}Usage Examples:
import { useInViewport } from "@mantine/hooks";
function FadeInOnScroll({ children }: { children: React.ReactNode }) {
const { ref, inViewport } = useInViewport({
threshold: 0.3,
});
return (
<div
ref={ref}
style={{
opacity: inViewport ? 1 : 0,
transform: inViewport ? 'translateY(0)' : 'translateY(20px)',
transition: 'opacity 0.6s ease, transform 0.6s ease',
}}
>
{children}
</div>
);
}
// Analytics tracking
function AnalyticsTracker({ eventName }: { eventName: string }) {
const { ref, inViewport } = useInViewport({
threshold: 0.5,
});
useEffect(() => {
if (inViewport) {
analytics.track(`${eventName}_viewed`);
}
}, [inViewport, eventName]);
return <div ref={ref}>Tracked content</div>;
}import { useIntersection } from "@mantine/hooks";
function LazyLoadContainer({ items }: { items: any[] }) {
const [visibleItems, setVisibleItems] = useState(items.slice(0, 10));
const { ref, entry } = useIntersection({
threshold: 0.1,
rootMargin: '100px', // Load before reaching the bottom
});
useEffect(() => {
if (entry?.isIntersecting && visibleItems.length < items.length) {
setVisibleItems(prev => [
...prev,
...items.slice(prev.length, prev.length + 10)
]);
}
}, [entry?.isIntersecting, visibleItems.length, items]);
return (
<div>
{visibleItems.map((item, index) => (
<ItemComponent key={item.id} {...item} />
))}
{visibleItems.length < items.length && (
<div ref={ref} style={{ height: '50px', textAlign: 'center' }}>
Loading more items...
</div>
)}
</div>
);
}import { useElementSize } from "@mantine/hooks";
function ResponsiveGrid({ items }: { items: any[] }) {
const { ref, width } = useElementSize();
const getColumns = (containerWidth: number) => {
if (containerWidth < 600) return 1;
if (containerWidth < 900) return 2;
if (containerWidth < 1200) return 3;
return 4;
};
const columns = getColumns(width);
return (
<div
ref={ref}
style={{
display: 'grid',
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: '16px',
}}
>
{items.map(item => (
<GridItem key={item.id} {...item} />
))}
</div>
);
}import { useMutationObserver } from "@mantine/hooks";
function ContentChangeTracker({ children }: { children: React.ReactNode }) {
const [lastChange, setLastChange] = useState<Date | null>(null);
const [changeLog, setChangeLog] = useState<string[]>([]);
const ref = useMutationObserver<HTMLDivElement>(
(mutations) => {
const now = new Date();
setLastChange(now);
const changes = mutations.map(mutation => {
switch (mutation.type) {
case 'childList':
return `Child nodes changed: +${mutation.addedNodes.length} -${mutation.removedNodes.length}`;
case 'attributes':
return `Attribute "${mutation.attributeName}" changed`;
case 'characterData':
return 'Text content changed';
default:
return 'Unknown change';
}
});
setChangeLog(prev => [...prev.slice(-9), ...changes]);
},
{
childList: true,
attributes: true,
characterData: true,
subtree: true,
}
);
return (
<div>
<div style={{ marginBottom: '16px', padding: '8px', background: '#f5f5f5' }}>
<h3>Change Log</h3>
<p>Last change: {lastChange?.toLocaleTimeString() || 'None'}</p>
<ul style={{ maxHeight: '100px', overflow: 'auto' }}>
{changeLog.map((change, index) => (
<li key={index}>{change}</li>
))}
</ul>
</div>
<div ref={ref}>
{children}
</div>
</div>
);
}