> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
> Use this file to discover all available pages before exploring further.

# useRef

> Returns a mutable ref object that persists for the component's lifetime

`useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument. The returned object persists for the full lifetime of the component.

## Signature

```typescript theme={null}
function useRef<T>(initialValue: T): RefObject<T>
function useRef<T>(initialValue: T | null): RefObject<T | null>
function useRef<T>(initialValue: T | undefined): RefObject<T | undefined>
```

## Parameters

<ParamField path="initialValue" type="T" required>
  The initial value to store in the ref object's `.current` property. Can be of any type. After initialization, you can mutate the `.current` property freely.
</ParamField>

## Returns

Returns a mutable ref object with a single property:

* **`current`**: Initially set to `initialValue`. You can read and write to this property. Changes to it do not cause re-renders.

## Accessing DOM Elements

```jsx theme={null}
import { useRef } from 'preact/hooks';

function TextInput() {
  const inputRef = useRef(null);

  const focusInput = () => {
    // Access DOM element and call its method
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}
```

## Storing Mutable Values

```jsx theme={null}
function Timer() {
  const [count, setCount] = useState(0);
  const intervalRef = useRef(null);

  const start = () => {
    if (intervalRef.current !== null) return;

    intervalRef.current = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
  };

  const stop = () => {
    if (intervalRef.current !== null) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </div>
  );
}
```

## Keeping Previous Values

```jsx theme={null}
function Counter({ value }) {
  const previousValue = useRef(value);

  useEffect(() => {
    previousValue.current = value;
  }, [value]);

  return (
    <div>
      <p>Current: {value}</p>
      <p>Previous: {previousValue.current}</p>
    </div>
  );
}
```

## Avoiding Stale Closures

```jsx theme={null}
function ChatRoom({ roomId }) {
  const [message, setMessage] = useState('');
  const callbackRef = useRef(null);

  // Store latest callback in ref
  callbackRef.current = () => {
    console.log(`Sending "${message}" to room ${roomId}`);
  };

  useEffect(() => {
    const interval = setInterval(() => {
      // Always calls the latest callback
      callbackRef.current?.();
    }, 5000);

    return () => clearInterval(interval);
  }, [roomId]); // Only re-subscribe when roomId changes

  return (
    <input
      value={message}
      onChange={e => setMessage(e.target.value)}
    />
  );
}
```

## Measuring DOM Elements

```jsx theme={null}
function MeasureBox() {
  const boxRef = useRef(null);
  const [dimensions, setDimensions] = useState({ width: 0, height: 0 });

  useLayoutEffect(() => {
    if (boxRef.current) {
      const { width, height } = boxRef.current.getBoundingClientRect();
      setDimensions({ width, height });
    }
  }, []);

  return (
    <div>
      <div ref={boxRef} style={{ width: '50%', height: '200px' }}>
        Content
      </div>
      <p>Width: {dimensions.width}px</p>
      <p>Height: {dimensions.height}px</p>
    </div>
  );
}
```

## Implementing Instance Variables

```jsx theme={null}
function VideoPlayer({ src }) {
  const videoRef = useRef(null);
  const isPlayingRef = useRef(false);
  const [, forceUpdate] = useState();

  const togglePlay = () => {
    if (isPlayingRef.current) {
      videoRef.current.pause();
      isPlayingRef.current = false;
    } else {
      videoRef.current.play();
      isPlayingRef.current = true;
    }
    forceUpdate({}); // Force re-render to update button text
  };

  return (
    <div>
      <video ref={videoRef} src={src} />
      <button onClick={togglePlay}>
        {isPlayingRef.current ? 'Pause' : 'Play'}
      </button>
    </div>
  );
}
```

## Tracking Render Count

```jsx theme={null}
function RenderCounter() {
  const renderCount = useRef(0);

  // Increment on every render without causing re-render
  renderCount.current++;

  return <div>This component has rendered {renderCount.current} times</div>;
}
```

## Forwarding Refs

```jsx theme={null}
import { forwardRef, useRef } from 'preact/compat';

const FancyInput = forwardRef((props, ref) => {
  return <input ref={ref} className="fancy-input" {...props} />;
});

function Parent() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <FancyInput ref={inputRef} />
      <button onClick={focusInput}>Focus</button>
    </div>
  );
}
```

## Debouncing with Ref

```jsx theme={null}
function SearchInput() {
  const [query, setQuery] = useState('');
  const timeoutRef = useRef(null);

  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value);

    // Clear previous timeout
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }

    // Set new timeout
    timeoutRef.current = setTimeout(() => {
      console.log('Searching for:', value);
      // Perform search
    }, 500);
  };

  return <input value={query} onChange={handleChange} />;
}
```

<Note>
  `useRef` is useful for more than just the `ref` attribute. It's handy for keeping any mutable value around, similar to how you'd use instance fields in classes.
</Note>

<Note>
  Mutating the `.current` property does **not** cause a re-render. If you need to trigger a re-render when a value changes, use `useState` instead.
</Note>

<Note>
  The ref object returned by `useRef` is the same object on every render. It's a plain JavaScript object that you can mutate freely.
</Note>
