๐ React Use Current โ Reactive + Synchronous State in React
React gives us two main primitives for storing state:
โ useState
- Reactive (re-renders UI)
-
Not synchronous (updates batch, no immediate
.value) - Forces immutability
- Requires creating new references (
setState({ ... }))
โ useRef
- Synchronous (
ref.current = x) - Not reactive (no re-renders when changed)
- No tracking
- No deep mutation detection
โ๏ธ useCurrent (built on VRef)
- Reactive (mutations trigger re-render)
- Synchronous (updated instantly like refs)
- Mutable (no cloning, no setState)
- Deep tracking (powered by VRef)
- Fast & GC-safe thanks to VRef
This hook gives React something it never had out-of-the-box:
Direct mutation that triggers re-renders โ immediately and safely.
๐ What Is React Use Current?
react-use-current is a tiny hook built on top of VRef (vref).
It gives React the ability to:
- Mutate values naturally (
user.age += 1) - Track changes deeply
- Trigger re-renders synchronously
- Work with objects, arrays, nested data
No need for setState(), shallow copying, or immutable patterns.
npm install react-use-current
๐งช Quick Example
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
๐ง Why Does This Hook Exist?
React developers often hit these problems:
โ "I need immediate state updates"
useState doesn't update until next render.
useCurrent updates instantly.
โ "I want to mutate state directly (nested objects)"
useState forces immutability โ slow & annoying.
useCurrent allows:
user.address.city = "Phnom Penh";
โ "useRef doesn't re-render when changed"
ref.current++ won't update UI.
useCurrent will.
๐ Comparison Table
| Feature | useState | useRef | useCurrent |
|---|---|---|---|
| Reactive | โ๏ธ | โ | โ๏ธ |
| Synchronous | โ | โ๏ธ | โ๏ธ |
| Deep mutation | โ | โ๏ธ | โ๏ธ |
| Triggers re-render | โ๏ธ | โ | โ๏ธ |
| Requires immutable updates | โ๏ธ | โ | โ |
| Built on VRef | โ | โ | โ๏ธ |
๐ How It Works (In Short)
-
useCurrent()internally wraps your initial value using VRef's reactive system. - Any mutation (
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. - Works deeply โ arrays, objects, nested structures.
๐งฉ Real Example โ Objects, Deep Mutation, and Tracking
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>
);
}
๐ง Auto-Tracking Helpers
These come from react-use-current (optional but powerful)
๐ฆ useApply
A 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)]);
๐ง useCompute
A 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)]);
๐งฌ Understanding the track() Function
track() converts reactive values into new value that React can detect in dependency arrays.
const updatedAt = track(user); // reactive object
Tracking is required for:
useEffectuseMemo- dependency change detection
This mechanism is identical to VRef's change reporters โ but adapted for React.
๐ฆ Real Use Cases
โ Complex forms
Directly mutate nested form fields without cloning.
โ Synchronous logic (counters, timers, scrolling)
Get immediate updatesโno batching.
โ Local reactive stores
Like lightweight MobX-style state.
โ Avoid expensive cloning in large objects
Mutate in place, but still reactive.
๐ฎ Live Playground
Play with react-use-current:
๐ Open Live Playground
๐ฆ Try It
๐ข 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?
Top comments (0)