Understanding useRef Hook in React

The useRef hook in React is a powerful tool for managing mutable values and accessing DOM elements. It allows you to create a mutable ref object that persists across renders without causing re-renders. This can be particularly useful for scenarios where you need to store a value between renders or interact with DOM elements imperatively.

useRef

const [name, setname] = useState('')
const [render, setrender] = useState(0)
useEffect(() => {
    setrender(prev => prev + 1)
}, [name])


return ( <>
    <input type="text" value={name} onChange={(e) => setname(e.target.value)} />
    <h2>My name is {name}</h2>
    <p>You change name value {render} times</p>
</> )

When we use useState it re-render components when state value change but some times we cannot re-render component when state variable value change, so that time we use useRef, it cannot re-render component when ref value change but it change only ref variable value, useRef is mutable.

useRef is completely separate from re-render components cycle, it is similar to useState.

const [name, setname] = useState('')
const render = useRef(0)
useEffect(() => {
    render.current = render.current + 1
})

return ( <>
    <input type="text" value={name} onChange={(e) => setname(e.target.value)} />
    <h2>My name is {name}</h2>
    <p>You change name value {render.current} times</p>
</> )

useRef also use for handle DOM objects, when we create a button that onClick focus goes to input field like a javascript DOM event, we create using with useRef in functional components.

const [name, setname] = useState('Parth')
const username = useRef()

return (<>
    <input ref={username} value={name}
        onChange={(e) => setname(e.target.value)} disabled={true} />
    <h2>My name is {name}</h2>
    <button onClick={() => {
        username.current.attributes.removeNamedItem('disabled')
        username.current.focus()
    }}>Edit ✎</button>
    <button onClick={() => {
        username.current.setAttribute("disabled", "true")
    }}>Edited ✔</button>
</>)

Using useRef to Manage Render Counts

When we want to track the number of times a component renders without causing re-renders, we can use useRef. Here's an example:

import React, { useState, useRef, useEffect } from 'react';

const RenderCountExample = () => {
    const [name, setName] = useState('');
    const renderCount = useRef(0);

    useEffect(() => {
        renderCount.current++;
    }, [name]);

    return (
        <>
            <input 
                type="text" 
                value={name} 
                onChange={(e) => setName(e.target.value)} 
            />
            <h2>My name is {name}</h2>
            <p>You've changed the name value {renderCount.current} times</p>
        </>
    );
};

In this example, renderCount is a ref object initialized with a value of 0. We increment its value every time the name state changes, and it persists across renders without causing the component to re-render.

Info

Using useRef allows us to manage mutable values without triggering re-renders, making it suitable for scenarios where we need to track values across renders.

Using useRef to Access DOM Elements

useRef can also be used to access DOM elements directly. Here's an example:

import React, { useState, useRef } from 'react';

const FocusInputExample = () => {
    const [name, setName] = useState('Parth');
    const inputRef = useRef();

    const handleEdit = () => {
        inputRef.current.removeAttribute('disabled');
        inputRef.current.focus();
    };

    const handleEdited = () => {
        inputRef.current.setAttribute('disabled', 'true');
    };

    return (
        <>
            <input 
                ref={inputRef} 
                value={name}
                onChange={(e) => setName(e.target.value)} 
                disabled
            />
            <h2>My name is {name}</h2>
            <button onClick={handleEdit}>Edit ✎</button>
            <button onClick={handleEdited}>Edited ✔</button>
        </>
    );
};

In this example, we use useRef to create a ref for the input field. We can then imperatively focus on the input field or modify its attributes without causing re-renders.

Task

Practice Using useRef

Objective: Create a component that focuses on an input field and enables/disables it based on button clicks.

  1. Create a FocusInput Component:

    Create a new file FocusInput.jsx and define a component that includes an input field and two buttons.

  2. Implement useRef:

    Utilize the useRef hook to access the input field directly.

  3. Handle Button Clicks:

    Implement functions to handle button clicks:

    • One function should focus on the input field when the "Edit" button is clicked.
    • Another function should enable/disable the input field when the "Edited" button is clicked.
  4. Render the Component:

    Import and render the FocusInput component in your application to test its functionality.