React gives us two main primitives for storing state:
useState.value)setState({ ... }))useRefref.current = x)useCurrent (built on VRef)This hook gives React something it never had out-of-the-box:
Direct mutation that triggers re-renders โ immediately and safely.
react-use-current is a tiny hook built on top of VRef (vref).
It gives React the ability to:
user.age += 1)No need for setState(), shallow copying, or immutable patterns.
npm install react-use-current
import useCurrent from "react-use-current"; export default function Counter() { const count = useCurrent(0); return ( <button onClick={() => (count.value += 1)}> Count: {count.value} </button> ); }
โ updates instantly
โ mutates directly
โ re-renders correctly
React developers often hit these problems:
useState doesn't update until next render.
useCurrent updates instantly.
useState forces immutability โ slow & annoying.
useCurrent allows:
user.address.city = "Phnom Penh";
ref.current++ won't update UI.
useCurrent will.
| Feature | useState | useRef | useCurrent |
|---|---|---|---|
| Reactive | โ๏ธ | โ | โ๏ธ |
| Synchronous | โ | โ๏ธ | โ๏ธ |
| Deep mutation | โ | โ๏ธ | โ๏ธ |
| Triggers re-render | โ๏ธ | โ | โ๏ธ |
| Requires immutable updates | โ๏ธ | โ | โ |
| Built on VRef | โ | โ | โ๏ธ |
useCurrent() internally wraps your initial value using VRef's reactive system.obj.key = value) triggers VRef's change event.useCurrent() listens to that event and updates an internal state token, which triggers a React re-render.import { useEffect, useMemo } from "react"; import useCurrent, { track } from "react-use-current"; export default function UserCard() { const { value: user } = useCurrent({ name: "John", age: 25, }); // Run whenever user changes (deep) useEffect(() => { console.log("User mutated:", user); }, [track(user)]); // Memo recomputes when specific field changes const isAdult = useMemo(() => user.age >= 18, [track(user.age)]); // track for primitive is optional return ( <div> <p>{user.name} โ {user.age}</p> <button onClick={() => (user.age += 1)}>Increase Age</button> <button onClick={() => (user.name = "Doe")}> Change Name </button> </div> ); }
react-use-current (optional but powerful)useApplyA version of useEffect that auto-tracks dependencies.
import { useApply } from "react-use-current"; useApply(() => { console.log("User changed:", user); }, [user]);
Equivalent to:
useEffect(() => {}, [track(user)]);
useComputeA version of useMemo that auto-tracks dependencies.
import { useCompute } from "react-use-current"; const isAdult = useCompute(() => { return user.age >= 18; }, [user.age]);
Equivalent to:
useMemo(() => ..., [track(user.age)]);
track() Functiontrack() converts reactive values into new value that React can detect in dependency arrays.
const updatedAt = track(user); // reactive object
Tracking is required for:
useEffectuseMemoThis mechanism is identical to VRef's change reporters โ but adapted for React.
Directly mutate nested form fields without cloning.
Get immediate updatesโno batching.
Like lightweight MobX-style state.
Mutate in place, but still reactive.
Play with react-use-current:
๐ Open Live Playground
๐ข npm: https://www.npmjs.com/package/react-use-current
๐ GitHub: https://github.com/JohnSoatra/react-use-current
Reference:
๐ Docs: https://doc.soatra.com/vref (VRef base)
๐ฌ What do you think?
What do you think?
Would this help in forms, real-time state, animations, or nested data?
๐ฌ Contact me ๐ LinkedIn โ John Soatra