# useCallback

The `useCallback` hook is used to avoid re-creating functions during every execution of the hook. That helps to reduce the need to rebind event handlers and to create a more stable API from your own hooks.

## Syntax

`useCallback(callbackFunction: Function, cacheKeyProperties: Array<Any>): Function`

`useCallback` accepts a function and, [just like useEffect](https://melody-js.gitbook.io/docs/useeffect#execute-a-side-effect-when-needed), an array of cache keys which determine when to re-create the callback.

{% tabs %}
{% tab title="ToggleButton.js" %}

```javascript
function useToggleButtonState({ handleClick }) {
    const [isToggled, setToggled] = useState(false);
    const handler = useCallback(event => {
        handleClick(event);
        // when using an updater function to mutate the state,
        // we will always operate on the latest value and won't
        // need to depend on it
        setToggled(toggled => !toggled);
        // we rely on the handleClick prop which could change
        // thus we need to specify it in the array
    }, [handleClick]);
    return {
        handler,
        isToggled
    };
}
```

{% endtab %}

{% tab title="ToggleButton.twig" %}

```markup
<button
    class="{{ isToggled ? 'selected' : 'not-selected'}}"
    onclick="{{ handler }}"
>Toggle me</button>
```

{% endtab %}
{% endtabs %}

In the example above the callback will always be the same as long as the `handleClick` property stays the same. We express that dependency by including it in the `cacheKeyProperties` array.

As a consequence, Melody will only need to attach and remove the event handler when `handleClick` is changed.

## Reducing dependencies

Given an empty array, `useCallback` will always return the very first function it has ever received. That's the ideal case that you should always try to achieve. The [updater function](https://melody-js.gitbook.io/docs/usestate#computing-an-update) as well as [useAtom](https://melody-js.gitbook.io/docs/melody-hooks-api/useatom) can help you achieve this goal. However, sometimes, like in the previous use case, you will need to rebind because of changing event handlers. That can be avoided by embracing the platform more strongly and by using the native event dispatching mechanism instead.

{% tabs %}
{% tab title="ToggleButton.js" %}

```javascript
function useToggleButtonState() {
    const [isToggled, setToggled] = useAtom(false);
    const rootElement = useRef(null);
    const handler = useCallback(event => {
        event.stopPropagation();
        // instead of dealing with passed in event handlers, faking our own
        // event system, we can just dispatch a native event and leverage the
        // platform to deliver interesting events to anyone who wants to listen
        // see: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
        // for reference
        rootElement.dispatchEvent(new CustomEvent(
            'toggled',
            { detail: isToggled() }
        ));
        // the accessor function provided by useAtom also
        // allows us to avoid the dependency
        setToggled(!isToggled());
    }, []);
    return {
        rootElement,
        handler,
        isToggled: isToggled()
    };
}
```

{% endtab %}

{% tab title="ToggleButton.twig" %}

```markup
<button
    ref="{{ rootElement }}"
    class="{{ isToggled ? 'selected' : 'not-selected'}}"
    onclick="{{ handler }}"
>Toggle me</button>
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
We wanted to keep the example close to the original but of course this would've been a very good chance for us to migrate from `onclick` style event handlers to a proper ref handler to achieve a cleaner and simpler implementation.
{% endhint %}

## What you don't want to do...

Since hooks are generally a very new concept and lots of material is being written about them, there's also a very high chance that you'll face some very bad examples.

```javascript
function useToggleButtonState({ handleClick }) {
    const [isToggled, setToggled] = useState(false);
    const handler = useCallback(event => {
        handleClick(event);
        // This is the critical mistake
        setToggled(!isToggled);
    }, [isToggled, handleClick]);
    return {
        handler,
        isToggled
    };
}
```

In that example the callback depends on the toggled state. Thus, every time the user actually toggles the button, the callback will need to be re-created.

**How to avoid:** Reduce dependencies as much as you can. Any dependency that is not strictly necessary is a dependency too much.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://melody-js.gitbook.io/docs/melody-hooks-api/usecallback.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
