Falytom logoFALYTOM
Games
ToolsUI ComponentsServicesProductsAbout
LoginSign Up
menu
  1. Home
  2. /Web Development
  3. /React
  4. /Useref Hook
Your Progress0%
0 of 42 completed

React Topics

Getting Started

  • What is React?
  • React vs Vanilla JavaScript
  • Setting Up Your Environment
  • Your First React App

JSX Fundamentals

  • Introduction to JSX
  • JSX Expressions and Variables
  • Conditional Rendering
  • Lists and Keys
  • Styling in JSX

Components Basics

  • Function Components
  • Props
  • Children Prop
  • Props Destructuring
  • Component Composition

State Management

  • Introduction to State
  • useState Hook
  • State Updates and Re-renders
  • Multiple State Variables
  • State Best Practices

Events and Interactivity

  • Handling Events
  • Event Objects
  • Forms in React
  • Form Validation

Side Effects and Data

  • Introduction to useEffect
  • Data Fetching
  • Cleanup Functions
  • Dependency Arrays

Advanced Hooks

  • useRef Hook
  • useContext Hook
  • useMemo Hook
  • useCallback Hook

React Patterns

  • Custom Hooks
  • Higher-Order Components
  • Render Props Pattern

React Router

  • Introduction to React Router
  • Routes and Navigation
  • Dynamic Routes and Parameters

Best Practices

  • Component Organization
  • Performance Optimization
  • Error Handling
  • Testing React Components

Real World Project

  • Building a Complete App

useRef Hook

Accessing DOM elements and storing mutable values

The useRef hook is one of React's most versatile tools. It lets you access DOM elements directly (like focusing an input), and store values that persist between renders without triggering re-renders (like tracking previous state or storing timers). While useState is for values that should trigger re-renders, useRef is for values that shouldn't. Let's explore everything useRef can do! šŸŽÆ

What Is useRef?

useRef creates a mutable object that persists across renders:

useref-basic.jsx
function Component() {
  const ref = React.useRef(initialValue)
  
  // ref is an object: { current: initialValue }
  console.log(ref.current)  // Access the value
  
  ref.current = 'new value'  // Update the value (no re-render!)
  
  return <div>Component</div>
}

// Key points:
// 1. useRef returns an object with a 'current' property
// 2. ref.current can be read and updated
// 3. Updating ref.current does NOT trigger re-render
// 4. Ref persists across renders (same object every time)

useRef vs useState:

useState:
• Triggers re-render when updated
• For UI-related data
• Asynchronous updates

useRef:
• Does NOT trigger re-render
• For non-UI data or DOM access
• Synchronous updates

Use Case 1: Accessing DOM Elements

The most common use of useRef is to access DOM elements directly:

Focusing an Input

focus-input.jsx
function SearchBox() {
  const inputRef = React.useRef(null)
  
  const handleClick = () => {
    // Access the actual DOM element
    inputRef.current.focus()
  }
  
  return (
    <div>
      <input ref={inputRef} type="text" placeholder="Search..." />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  )
}

// How it works:
// 1. Create ref with useRef(null)
// 2. Pass ref to element's ref prop
// 3. After render, ref.current = DOM element
// 4. Can call DOM methods like .focus()

Scrolling to Element

scroll-to.jsx
function ScrollDemo() {
  const sectionRef = React.useRef(null)
  
  const scrollToSection = () => {
    sectionRef.current.scrollIntoView({ 
      behavior: 'smooth' 
    })
  }
  
  return (
    <div>
      <button onClick={scrollToSection}>Scroll to Section</button>
      
      <div style={{ height: '1000px' }}>
        {/* Lots of content */}
      </div>
      
      <div ref={sectionRef}>
        <h2>Important Section</h2>
        <p>Content here...</p>
      </div>
    </div>
  )
}

Playing/Pausing Video

video-control.jsx
function VideoPlayer() {
  const videoRef = React.useRef(null)
  
  const play = () => {
    videoRef.current.play()
  }
  
  const pause = () => {
    videoRef.current.pause()
  }
  
  return (
    <div>
      <video ref={videoRef} src="/video.mp4" />
      <button onClick={play}>Play</button>
      <button onClick={pause}>Pause</button>
    </div>
  )
}

Getting Element Dimensions

element-dimensions.jsx
function MeasureBox() {
  const boxRef = React.useRef(null)
  const [dimensions, setDimensions] = React.useState({ width: 0, height: 0 })
  
  const measure = () => {
    const box = boxRef.current
    setDimensions({
      width: box.offsetWidth,
      height: box.offsetHeight
    })
  }
  
  return (
    <div>
      <div 
        ref={boxRef}
        style={{ width: '200px', height: '100px', background: 'lightblue' }}
      >
        Box to measure
      </div>
      <button onClick={measure}>Measure</button>
      <p>Width: {dimensions.width}px</p>
      <p>Height: {dimensions.height}px</p>
    </div>
  )
}

āœ… DOM Access Best Practice

Use refs for imperative DOM operations:
• Focusing inputs
• Scrolling
• Playing media
• Measuring elements
• Integrating with non-React libraries

Don't use refs for things React can handle declaratively!

Use Case 2: Storing Mutable Values

Use refs to store values that shouldn't trigger re-renders:

Storing Previous State

previous-state.jsx
function Counter() {
  const [count, setCount] = React.useState(0)
  const prevCountRef = React.useRef(0)
  
  React.useEffect(() => {
    // Store current count after render
    prevCountRef.current = count
  })
  
  return (
    <div>
      <p>Current count: {count}</p>
      <p>Previous count: {prevCountRef.current}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  )
}

// How it works:
// 1. Component renders with count = 0, prevCountRef = 0
// 2. useEffect runs, sets prevCountRef = 0
// 3. User clicks, count becomes 1
// 4. Component renders with count = 1, prevCountRef still = 0 (shows previous!)
// 5. useEffect runs, sets prevCountRef = 1

Storing Timer IDs

timer-ref.jsx
function Stopwatch() {
  const [time, setTime] = React.useState(0)
  const [isRunning, setIsRunning] = React.useState(false)
  const intervalRef = React.useRef(null)
  
  const start = () => {
    setIsRunning(true)
    // Store interval ID in ref
    intervalRef.current = setInterval(() => {
      setTime(t => t + 1)
    }, 1000)
  }
  
  const stop = () => {
    setIsRunning(false)
    // Use ref to clear interval
    clearInterval(intervalRef.current)
  }
  
  const reset = () => {
    stop()
    setTime(0)
  }
  
  return (
    <div>
      <p>Time: {time}s</p>
      {!isRunning ? (
        <button onClick={start}>Start</button>
      ) : (
        <button onClick={stop}>Stop</button>
      )}
      <button onClick={reset}>Reset</button>
    </div>
  )
}

// Why use ref for interval ID?
// - Don't want re-render when storing ID
// - Need to access ID later to clear interval
// - Perfect use case for useRef!

Tracking Render Count

render-count.jsx
function Component() {
  const [name, setName] = React.useState('')
  const renderCount = React.useRef(0)
  
  // Increment on every render
  renderCount.current = renderCount.current + 1
  
  return (
    <div>
      <p>This component has rendered {renderCount.current} times</p>
      <input 
        value={name} 
        onChange={(e) => setName(e.target.value)}
        placeholder="Type to trigger re-renders"
      />
    </div>
  )
}

// Why this works:
// - renderCount.current updates don't trigger re-renders
// - Value persists across renders
// - Can see how many times component has rendered!

Caching Expensive Calculations

cache-ref.jsx
function DataProcessor({ data }) {
  const cacheRef = React.useRef({})
  
  const processData = (input) => {
    // Check cache
    if (cacheRef.current[input]) {
      console.log('Using cached result')
      return cacheRef.current[input]
    }
    
    // Expensive calculation
    console.log('Computing...')
    const result = expensiveOperation(input)
    
    // Store in cache
    cacheRef.current[input] = result
    return result
  }
  
  const result = processData(data)
  
  return <div>Result: {result}</div>
}

// Ref stores cache across renders without triggering re-renders
// Note: Usually useMemo is better for this, but this shows the concept!

When to Use Ref vs State

Use State When:

  • Value is displayed in UI
  • Changing value should trigger re-render
  • Value affects what's rendered
use-state-when.jsx
// āœ… Use state - value is displayed
function Counter() {
  const [count, setCount] = React.useState(0)
  
  return (
    <div>
      <p>Count: {count}</p>  {/* Displayed in UI */}
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  )
}

Use Ref When:

  • Accessing DOM elements
  • Storing values that shouldn't trigger re-render
  • Keeping track of previous values
  • Storing timer/subscription IDs
use-ref-when.jsx
// āœ… Use ref - just storing ID, not displaying
function Timer() {
  const [time, setTime] = React.useState(0)
  const intervalRef = React.useRef(null)  // Just storing ID
  
  const start = () => {
    intervalRef.current = setInterval(() => {
      setTime(t => t + 1)
    }, 1000)
  }
  
  return (
    <div>
      <p>Time: {time}</p>  {/* State for displayed value */}
      <button onClick={start}>Start</button>
    </div>
  )
}

Common Mistake: Using Ref for UI Data

āŒ Don't do this:
ref.current = newValue (and expect UI to update)

Updating ref.current doesn't trigger re-render!

āœ… Use state instead:
setState(newValue)

Interactive Demo

ReactPlayground.jsx
Code Editor
Preview

šŸ’” Tip: Edit the code above and click "Run" to see your changes

Common useRef Patterns

Pattern 1: Custom Input Hook

pattern-input-hook.jsx
function useAutoFocus() {
  const inputRef = React.useRef(null)
  
  React.useEffect(() => {
    inputRef.current.focus()
  }, [])
  
  return inputRef
}

// Usage:
function LoginForm() {
  const emailRef = useAutoFocus()
  
  return <input ref={emailRef} type="email" />
}

// Email input automatically focused on mount!

Pattern 2: Previous Value Hook

pattern-previous-hook.jsx
function usePrevious(value) {
  const ref = React.useRef()
  
  React.useEffect(() => {
    ref.current = value
  })
  
  return ref.current
}

// Usage:
function Counter() {
  const [count, setCount] = React.useState(0)
  const prevCount = usePrevious(count)
  
  return (
    <div>
      <p>Current: {count}</p>
      <p>Previous: {prevCount}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  )
}

Pattern 3: Debounce with Ref

pattern-debounce.jsx
function SearchBox() {
  const [query, setQuery] = React.useState('')
  const [results, setResults] = React.useState([])
  const timeoutRef = React.useRef(null)
  
  const handleChange = (e) => {
    const value = e.target.value
    setQuery(value)
    
    // Clear previous timeout
    clearTimeout(timeoutRef.current)
    
    // Set new timeout
    timeoutRef.current = setTimeout(() => {
      // Search after 500ms delay
      fetch(`/api/search?q=${value}`)
        .then(res => res.json())
        .then(data => setResults(data))
    }, 500)
  }
  
  return (
    <div>
      <input value={query} onChange={handleChange} />
      <ul>
        {results.map(item => <li key={item.id}>{item.name}</li>)}
      </ul>
    </div>
  )
}

Common useRef Mistakes

1. Expecting Re-render on Update

mistake-rerender.jsx
// āŒ Wrong - UI won't update
function Counter() {
  const countRef = React.useRef(0)
  
  const increment = () => {
    countRef.current += 1
    // Component won't re-render!
  }
  
  return (
    <div>
      <p>Count: {countRef.current}</p>  {/* Won't update! */}
      <button onClick={increment}>+</button>
    </div>
  )
}

// āœ… Correct - Use state for UI values
function Counter() {
  const [count, setCount] = React.useState(0)
  
  return (
    <div>
      <p>Count: {count}</p>  {/* Updates correctly! */}
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  )
}

2. Accessing Ref During Render

mistake-render-access.jsx
// āŒ Wrong - Don't read/write during render
function Component() {
  const ref = React.useRef(0)
  
  ref.current += 1  // Bad! Side effect during render
  
  return <div>{ref.current}</div>
}

// āœ… Correct - Use in event handler or effect
function Component() {
  const ref = React.useRef(0)
  
  React.useEffect(() => {
    ref.current += 1  // Good! In effect
  })
  
  const handleClick = () => {
    ref.current += 1  // Good! In event handler
  }
  
  return <button onClick={handleClick}>Click</button>
}

3. Forgetting .current

mistake-current.jsx
// āŒ Wrong - Ref IS the object, not the value
function Component() {
  const inputRef = React.useRef(null)
  
  const focus = () => {
    inputRef.focus()  // Error! inputRef is object, not element
  }
  
  return <input ref={inputRef} />
}

// āœ… Correct - Use .current to access value
function Component() {
  const inputRef = React.useRef(null)
  
  const focus = () => {
    inputRef.current.focus()  // Correct!
  }
  
  return <input ref={inputRef} />
}

Key Takeaways

  • useRef creates a mutable object that persists across renders
  • Ref object has a current property you can read/write
  • Updating ref.current does NOT trigger re-render
  • Use Case 1: Accessing DOM elements (focus, scroll, measure)
  • Use Case 2: Storing values that shouldn't trigger re-renders
  • Pass ref to element's ref prop to access DOM
  • Use state for UI values, use ref for non-UI values
  • Common uses: timers, previous values, render counts, caching
  • Don't read/write refs during render (use effects or event handlers)
  • Refs are perfect for integrating with non-React libraries
  • Always access ref value with .current
  • Refs persist the same object identity across renders

What's Next?

You now understand useRef and when to use it! You know how to access DOM elements and store values that don't trigger re-renders.

In the next lesson, you'll learn about useContext Hook:

  • What is Context and why use it
  • Creating and providing context
  • Consuming context with useContext
  • Avoiding prop drilling
  • Common context patterns

Get ready to share state across your entire component tree without passing props! 🌳

Learning how to use useRef for DOM access and mutable values in React!

Previous
Dependency Arrays
Next
useContext Hook

Never Miss a New React Tutorial

Join 2,000+ developers learning React step-by-step. Get new tutorials, tips, and exclusive resources delivered to your inbox - completely FREE.

You might also like

UI Components

Ready-made components for your projects

Developer Tools

Boost productivity with handy generators

HTML Game

Learn HTML concepts through interactive gameplay

Join Our Web Development Training Program

Master frontend & backend development with hands-on projects.

React Tutorials

0 of 42 completed

Your Progress0%

Topics

Getting Started

  • What is React?
  • React vs Vanilla JavaScript
  • Setting Up Your Environment
  • Your First React App

JSX Fundamentals

  • Introduction to JSX
  • JSX Expressions and Variables
  • Conditional Rendering
  • Lists and Keys
  • Styling in JSX

Components Basics

  • Function Components
  • Props
  • Children Prop
  • Props Destructuring
  • Component Composition

State Management

  • Introduction to State
  • useState Hook
  • State Updates and Re-renders
  • Multiple State Variables
  • State Best Practices

Events and Interactivity

  • Handling Events
  • Event Objects
  • Forms in React
  • Form Validation

Side Effects and Data

  • Introduction to useEffect
  • Data Fetching
  • Cleanup Functions
  • Dependency Arrays

Advanced Hooks

  • useRef Hook
  • useContext Hook
  • useMemo Hook
  • useCallback Hook

React Patterns

  • Custom Hooks
  • Higher-Order Components
  • Render Props Pattern

React Router

  • Introduction to React Router
  • Routes and Navigation
  • Dynamic Routes and Parameters

Best Practices

  • Component Organization
  • Performance Optimization
  • Error Handling
  • Testing React Components

Real World Project

  • Building a Complete App
Falytom logoFALYTOM

Learn technologies like HTML, CSS, JavaScript, React, NodeJS and more through interactive games, tutorials, components and free tools. Transform your businesses with AI chatbots, SEO-optimized websites, and professional development services.

Ā© 2025 Tomilola Group
  • Facebook logo
  • Twitter logo
  • Instagram logo
  • LinkedIn logo
  • GitHub logo
  • YouTube logo