跪拜 Guibai
← All articles
Frontend · JavaScript

useRef Is React's Most Underrated Hook — It Handles DOM, Force Renders, and Web Workers

By 橘子星 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Misusing useState for non-UI data causes unnecessary renders that degrade performance in animations, real-time streams, and worker-heavy apps. Recognizing when a value should live in a ref instead of state is a cheap, high-leverage fix that every React developer can apply immediately.

Summary

React's useRef returns a plain `{ current }` container. Mutating `.current` never schedules a re-render, which separates it from useState. That property makes it the correct home for DOM node references, where a ref paired with useEffect replaces autoFocus with programmatic control at any lifecycle moment. The same non-reactive storage enables a forceRender pattern: a useState setter stripped of its state value acts as a manual refresh trigger, letting a ref accumulate high-frequency updates that only flush to the UI in batches. Web Worker instances fit the same model. A Worker runs off the main thread and has no business driving UI, so stashing it in a ref avoids pointless re-renders while keeping the reference alive across renders.

Takeaways
useRef returns a mutable `{ current }` object; changing `.current` never triggers a re-render.
DOM nodes are assigned to ref.current only after React commits them to the page, so any imperative DOM call must run inside useEffect.
autoFocus is a native browser attribute that works without JavaScript timing; useRef plus useEffect gives programmatic control at any point.
Combining useRef with a useState setter — discarding the state value itself — creates a forceRender trigger that decouples value changes from rendering.
Batching updates in a ref and flushing them selectively (e.g., every 5th increment) eliminates wasted renders in high-frequency counters or animation loops.
Web Worker instances belong in useRef, not useState, because they run off the main thread and have no connection to the UI.
JavaScript's single-threaded event loop freezes the page during long-running synchronous work; Workers move that work to a separate thread.
React's design expects useState for 90% of UI-driving state and useRef for the 10% of edge cases where values should persist without causing renders.
Conclusions

Many React beginners treat useRef as a niche DOM-access trick, but its core capability — non-reactive mutable storage — is a general-purpose primitive that solves a class of performance problems useState can't touch.

The forceRender pattern effectively repurposes a useState setter as a manual `requestRender()` call, which isn't documented as an official API but falls naturally out of how React's scheduler works.

Storing a Worker in useRef highlights a broader rule: any object whose lifecycle is independent of the UI tree (timers, sockets, WASM instances, third-party lib handles) should live in a ref to avoid coupling it to React's render cycle.

Concepts & terms
useRef
A React Hook that returns a mutable ref object with a `.current` property. The object persists for the full lifetime of the component, and mutating `.current` does not cause a re-render.
forceRender pattern
A technique where a useState setter is used solely to trigger a re-render, while the actual mutable data lives in a useRef. The state value itself is ignored (destructured with a comma placeholder), turning the setter into a manual refresh mechanism.
Web Worker
A browser API that runs JavaScript on a background thread, separate from the main UI thread. Workers communicate with the main thread via message passing, preventing long-running computations from freezing the page.
React commit phase
The stage in React's rendering process where the virtual DOM changes are applied to the actual DOM. Refs are populated during this phase, which is why DOM access must happen afterward — typically inside useEffect.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗