Current count: 0
No value captured yet
"use client";
import React from "react";
import { Button, Stack, Text, useLatestRef } from "@vortexlabs/vortex";
export const LatestValue = () => {
const [count, setCount] = React.useState(0);
const [captured, setCaptured] = React.useState<number | null>(null);
const [pending, setPending] = React.useState(false);
const latestCount = useLatestRef(count);
const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null);
React.useEffect(
() => () => {
if (timer.current !== null) clearTimeout(timer.current);
},
[],
);
const captureLater = () => {
setPending(true);
timer.current = setTimeout(() => {
setCaptured(latestCount.current);
setPending(false);
}, 2000);
};
return (
<Stack gap={3}>
<Text>Current count: {count}</Text>
<Stack direction="row" gap={2} wrap>
<Button onClick={() => setCount(count + 1)}>Increment</Button>
<Button variant="secondary" onClick={captureLater} disabled={pending}>
{pending ? "Waiting two seconds…" : "Capture in two seconds"}
</Button>
</Stack>
<Text attributes={{ role: "status" }}>
{captured === null ? "No value captured yet" : `Captured count: ${captured}`}
</Text>
</Stack>
);
};Features
- Keeps the same ref object across renders.
- Updates
.currentafter a committed value change. - Keeps values available to delayed callbacks.
Pass a value and read it through .current. Ref updates do not trigger renders; use state for visible UI.
Keeping a Callback Current
Wrap a changing callback so an existing event listener can read it without subscribing again.
"use client";
import React from "react";
import { useLatestRef } from "@vortexlabs/vortex";
export const useWindowResize = (onResize: () => void) => {
const callbackRef = useLatestRef(onResize);
React.useEffect(() => {
const handleResize = () => callbackRef.current();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, [callbackRef]);
};The first value is available immediately. Later values update after React commits, so .current can still hold the previous value during render.
Keep subscription targets in effect dependencies. A ref keeps a callback current; it does not replace cleanup when the target changes.