Create your own hooks

In this guide we will cover how to create your own hooks by combining the existing ones.


Introduction

We know that the existing hooks will not satisfy every single exigency that a developer can have while developing Wompo Components, but they are the base that allows developers to satisfy those needs. You can create your own custom hooks that can then be used across all components.


Combining hooks

We can't stress it enough: hooks are supposed to be used only inside a component.

...or...

inside other hooks!

Exactly, you can create a custom function (hook) that executes other hooks on it. Of course, this function is supposed to only be called inside a component (or eventually another hook).
As said before, native hooks are the base: they have the main functionalities and concepts that can be combined together to create more advanced and complex hooks. Let's see how.


Example: useLocalStorage

Let's dive into the first example: a hook that allows to use the local storage easily.

import { useState, useCallback } from 'wompo';

function useLocalStorage(key, defaultValue) {
  // Initialize state
  const [value, setValue] = useState(null);
  // Create a custom setter function to set the localStorage value
  const setter = useCallback((newValue) => {
    localStorage.setItem(key, newValue);
    setValue(newValue);
  });
  // We get the localStorage value only the first time
  if (value === null) {
    const storedItem = localStorage.getItem(key);
    if (storedItem === null) {
      // If no value is seved we initialize it with the default value.
      setter(defaultValue);
    } else {
      // Otherwise, we just set the current value with the one in the localStorage
      setter(storedItem);
    }
  }
  return [value, setter];
}

Easy, isn't it? We combined the useState hook and the useCallback hook to create the custom useLocalStorage hook. This hook will accept a key and a default value, and will return the current value and a setter function to set a new value to the local storage. Thank to the useState hook, the component will also be automatically re-rendered when you update the storage.

If you return a function in your custom hook, you should always wrap it around the useCallback hook so that, if used as a parameter for other components, it'll not cause a useless re-render.


Example: useTime

Another example can be a hook that will start counting the number of seconds since the component was first rendered (we personally don't have a clear idea of why it should be useful, but we think it's cool). This hook will not update the component: it will only count.

import { useRef, useEffect } from 'wompo';

export default function useTime() {
  // Initialize the timer
  const timeRef = useRef(0);
  // Start the timer when the component is rendered for the first time
  useEffect(() => {
    const intervalId = setInterval(() => {
      // Update the timer by one every second.
      timeRef.current += 1;
    }, 1000);
    // When the component is unmounted, stop the interval.
    return () => {
      clearInterval(intervalId);
    };
  }, []);
  return timeRef;
}

And then, in a component:

import { defineWompo, html } from 'wompo';
import useTime from './useTime';

function Component() {
  const timeSinceFirstRender = useTime();
  const showTime = () => {
    alert(`I was rendered ${timeSinceFirstRender.current} seconds ago`);
  };
  return html`
    <button @click=${showTime}>
      If you click me I'll show you how many seconds ago I was rendered!
    </button>
  `;
}
defineWompo(Component);

Result:


Advanced hooks

You can create your own hooks from scratch without combining all the already existing hooks (you still need to use at least one). This is an advanced case, and should always be avoided when possible. If you want to know more, check the useHook hook reference.