> ## 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.

# useCallback

> Returns a memoized callback function

`useCallback` returns a memoized version of the callback that only changes if one of the dependencies has changed. This is useful for passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.

## Signature

```typescript theme={null}
function useCallback<T extends Function>(
  callback: T,
  inputs: ReadonlyArray<unknown>
): T
```

## Parameters

<ParamField path="callback" type="T extends Function" required>
  The callback function to memoize. This function will be returned on subsequent renders if the dependencies haven't changed.
</ParamField>

<ParamField path="inputs" type="ReadonlyArray<unknown>" required>
  An array of dependencies. The callback will only be recreated if one of these values changes (compared using `===`).
</ParamField>

## Returns

Returns the memoized callback function of type `T`. On the initial render, it returns the passed callback. On subsequent renders, it returns the same callback reference if dependencies haven't changed, or a new callback if they have.

## Basic Usage

```jsx theme={null}
import { useCallback, useState } from 'preact/hooks';
import { memo } from 'preact/compat';

const Button = memo(({ onClick, children }) => {
  console.log('Button rendered');
  return <button onClick={onClick}>{children}</button>;
});

function Parent() {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(0);

  // Memoize callback to prevent Button re-renders
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []); // No dependencies, never recreated

  return (
    <div>
      <p>Count: {count}</p>
      <Button onClick={increment}>Increment</Button>
      <button onClick={() => setOtherState(s => s + 1)}>
        Other State: {otherState}
      </button>
    </div>
  );
}
```

## With Dependencies

```jsx theme={null}
function SearchResults({ query, category }) {
  const [results, setResults] = useState([]);

  // Recreate callback when query or category changes
  const handleSearch = useCallback(async () => {
    const data = await fetch(`/api/search?q=${query}&cat=${category}`);
    const json = await data.json();
    setResults(json);
  }, [query, category]);

  return (
    <div>
      <button onClick={handleSearch}>Search</button>
      <ResultsList results={results} />
    </div>
  );
}
```

## Passing to Child Components

```jsx theme={null}
const TodoItem = memo(({ todo, onToggle, onDelete }) => {
  console.log('TodoItem rendered:', todo.id);
  return (
    <div>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => onToggle(todo.id)}
      />
      <span>{todo.text}</span>
      <button onClick={() => onDelete(todo.id)}>Delete</button>
    </div>
  );
});

function TodoList() {
  const [todos, setTodos] = useState([]);

  const handleToggle = useCallback((id) => {
    setTodos(prev => prev.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ));
  }, []);

  const handleDelete = useCallback((id) => {
    setTodos(prev => prev.filter(todo => todo.id !== id));
  }, []);

  return (
    <div>
      {todos.map(todo => (
        <TodoItem
          key={todo.id}
          todo={todo}
          onToggle={handleToggle}
          onDelete={handleDelete}
        />
      ))}
    </div>
  );
}
```

## Event Handlers

```jsx theme={null}
function Form({ userId, onSubmit }) {
  const [formData, setFormData] = useState({ name: '', email: '' });

  const handleChange = useCallback((field) => {
    return (e) => {
      setFormData(prev => ({
        ...prev,
        [field]: e.target.value
      }));
    };
  }, []);

  const handleSubmit = useCallback((e) => {
    e.preventDefault();
    onSubmit({ ...formData, userId });
  }, [formData, userId, onSubmit]);

  return (
    <form onSubmit={handleSubmit}>
      <input value={formData.name} onChange={handleChange('name')} />
      <input value={formData.email} onChange={handleChange('email')} />
      <button type="submit">Submit</button>
    </form>
  );
}
```

## With useEffect

```jsx theme={null}
function DataFetcher({ url, params }) {
  const [data, setData] = useState(null);

  const fetchData = useCallback(async () => {
    const query = new URLSearchParams(params).toString();
    const response = await fetch(`${url}?${query}`);
    const json = await response.json();
    setData(json);
  }, [url, params]);

  useEffect(() => {
    fetchData();
  }, [fetchData]); // Safe to use as dependency

  return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}
```

## Debounced Callbacks

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

  const debouncedSearch = useCallback((value) => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }

    timeoutRef.current = setTimeout(() => {
      onSearch(value);
    }, 500);
  }, [onSearch]);

  const handleChange = useCallback((e) => {
    const value = e.target.value;
    setQuery(value);
    debouncedSearch(value);
  }, [debouncedSearch]);

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

## Callback Factories

```jsx theme={null}
function ItemList({ items, onItemClick }) {
  // Create memoized callback factory
  const createClickHandler = useCallback((item) => {
    return () => onItemClick(item);
  }, [onItemClick]);

  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>
          <button onClick={createClickHandler(item)}>
            {item.name}
          </button>
        </li>
      ))}
    </ul>
  );
}
```

## With Context

```jsx theme={null}
const ActionsContext = createContext();

function ActionsProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState);

  // Memoize all action creators
  const actions = useMemo(() => ({
    addItem: (item) => dispatch({ type: 'ADD_ITEM', payload: item }),
    removeItem: (id) => dispatch({ type: 'REMOVE_ITEM', payload: id }),
    updateItem: (item) => dispatch({ type: 'UPDATE_ITEM', payload: item })
  }), []);

  return (
    <ActionsContext.Provider value={actions}>
      {children}
    </ActionsContext.Provider>
  );
}

function Component() {
  const { addItem } = useContext(ActionsContext);

  // Safe to use in effects/callbacks
  const handleAdd = useCallback(() => {
    addItem({ id: Date.now(), text: 'New item' });
  }, [addItem]);

  return <button onClick={handleAdd}>Add Item</button>;
}
```

## Relationship with useMemo

```jsx theme={null}
// These are equivalent:
const memoizedCallback = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

const memoizedCallback = useMemo(() => {
  return () => {
    doSomething(a, b);
  };
}, [a, b]);
```

<Note>
  `useCallback(fn, deps)` is equivalent to `useMemo(() => fn, deps)`. It's a convenience hook specifically for memoizing functions.
</Note>

<Note>
  Use `useCallback` when passing callbacks to optimized child components (wrapped in `memo`) that rely on reference equality to prevent unnecessary renders.
</Note>

<Note>
  Don't use `useCallback` everywhere. Only use it when:

  * Passing callbacks to memoized child components
  * Using the callback as a dependency in other hooks like `useEffect`
  * The callback is expensive to create
</Note>
