1️⃣ Stopwatch Example — Understanding useRef with setInterval
Scenario:
I built a simple stopwatch using React to understand useRef and state updates.
Key Concepts:
Problem:
UsingsetStatedirectly insetIntervalcan lead to stale state issues:
setTime(time + 1) // Might use old `time` value
Solution:
Use the functional updater to access the latest state:
setTime(prevTime => prevTime + 1)
Why
useRefis important:
- Stores the interval ID across re-renders (
intervalRef.current). - Doesn’t trigger re-renders when updated.
- Allows us to clear the interval safely:
CODEclearInterval(intervalRef.current)
intervalRef.current = null
- Stores the interval ID across re-renders (
Important Takeaways:
useRef= persistent, mutable storage across renders.- Always clear old intervals before starting a new one to prevent multiple intervals running simultaneously.
useStatetriggers UI updates;useRefstores values silently.
2️⃣ useState vs let vs useRef
Scenario:
I experimented with a money variable using let, useState, and useRef to understand state management.
Key Observations:
Usinglet:
- Value changes in memory but does not trigger UI updates.
- Resets on re-renders since it’s recreated each time.
UsinguseState:
- Changes trigger re-renders, so updated values reflect in the UI.
UsinguseRef:
- Stores a persistent value across renders without triggering UI updates.
- Access using
.current. - Perfect for storing values like timers, previous state, or DOM references.
Memory Tip:
State = UI updatesRef = silent memory storage
3️⃣ Performance Optimization — useCallback and useMemo
Scenario:
Built a Fibonacci calculator to understand when recalculations happen unnecessarily.
Key Observations:
- Problem:
- Fibonacci function recalculates on every render, even if only unrelated state changes (
count) happen. - Causes unnecessary computation and slows performance.
- Solutions:
useCallback:
- Memoizes a function reference.
- Only recreates the function if dependencies change.
- Prevents unnecessary function recreation across re-renders.
useMemo:
- Memoizes the result of a calculation.
- Recalculates only if dependencies change (e.g., input value).
- Avoids unnecessary computation when unrelated state changes.
Memory Tip:
- Callback = remembers function
- Memo = remembers result
4️⃣ Important Lessons Learned
Re-renders: Functions and variables are recreated, but refs remain stable.
Intervals & Timers: Always store inuseRefand clear them to prevent duplicate runs.
State vs Ref: Use state for UI updates; use ref for persistent data without re-renders.
Performance Hooks:useCallbackanduseMemoprevent unnecessary recalculation and function recreation.
Debugging Tip: Always check console logs to confirm variable updates that don’t reflect in UI (common withletor ref values).
5️⃣ Practical Takeaways for Developers
- For timers or intervals, always store the reference in
useRef. - Use
useStatewhen UI needs to update,useRefwhen you want to persist values silently. - Use functional updates with
setStateto avoid stale closures. - Optimize performance with
useCallback(functions) anduseMemo(values). - Always clear intervals or timeouts to prevent memory leaks and bugs.
6️⃣ Memory Mnemonics
| Hook | Purpose | Tip |
|---|---|---|
useState | UI reactive value | State = UI updates |
useRef | Persistent storage across renders | Ref = silent memory |
useCallback | Memoize function references | Callback = remembers function |
useMemo | Memoize computed values | Memo = remembers result |
SOCIAL SHARE CARD GENERATOR