Melody Documentation
  • Why Melody?
  • Quickstart
    • What is Melody?
    • Tutorial
    • Installation
  • Templates
    • Twig
    • Mounting Components
    • Keys and Loops
    • Attributes
    • CSS Classes
    • Inline Styles
    • Refs
    • CSS Modules
  • Melody-Streams
    • Basic concept
    • A Step-by-Step Walkthrough
  • MELODY-STREAMS API
    • createComponent
    • The component function
  • melody-hooks
    • Overview
    • Rules of Hooks
    • Event Handling
    • Separation of Concerns
  • melody-hooks API
    • useState
    • useAtom
    • useEffect
    • useRef
    • useCallback
    • useMemo
    • useReducer
    • usePrevious
  • melody-component
    • Overview
  • melody-hoc
    • Overview
Powered by GitBook
On this page
  • Storing non-reactive values
  • Storing all referenced elements
  • Easy access to just a single referenced element

Was this helpful?

  1. melody-hooks API

useRef

The useRef hook is a multi-purpose hook. Its primary purpose in Melody is to store and update values without causing a re-evaluation of the state hook. Thus, you might say it offers a non-reactive value storage. Coming from React, it has inherited the name useRef and the additional capability to reference DOM elements. However, as mentioned in Event Handling, Melody offers better ways to bind DOM elements and you should not rely on useRef for that purpose.

The term "non-reactive" refers to a value that, when changed, does not cause the component to be re-evaluated. Values produced by useState or useAtom will cause re-evaluation whenever they are modified through the mutator function.

Storing non-reactive values

// a small hook to contain interval logic which can be canceled
function usePulse({ interval, callback }) {
    // create a ref
    const timer = useRef(null);
    // timer.current will contain our value over time and will always
    // refer to the latest value
    const cancel = useCallback(() => clearInterval(timer.current));
    useEffect(() => {
        // update the value with the new interval
        timer.current = setInterval(callback, interval);
        return cancel;
    }, [interval, callback]);
    // and return a function to cancel it
    return cancel;
}

function usePulseButton() {
    const [shouldPulseIn, setPulseIn, isPulseIn] = useAtom(true);
    // on each interval tick, we'll flip the pulse value
    // that'd then trigger a CSS class change to do an animation
    const cancelPulse = usePulse(1000, useCallback(() => {
        setPulseIn(!shouldPulseIn());
    }));
    const buttonRef = useCallback(element => {
        return fromEvent(element, 'click').subscribe(event => {
            // when the value is clicked we'll stop the animation
            // using the callback
            cancelPulse();
        });
    });
    return {
        buttonRef,
        isPulseIn
    };
}

Storing all referenced elements

function useReferencedElements() {
    // create a non-reactive variable which will hold all of our elements
    const elements = useRef([]);
    // use a normal ref handler to collect all referenced elements
    const refElement = useCallback(element => {
        elements.current.push(element);
        // and make sure we drop them from the list if anything changes
        return () => removeElement(elements.current, element);
    }, []);
    // provide easy access to the refHandler and the array of elements
    return [refElement, elements.current];
}

function useItemList({ data }) {
    const [item, itemElements] = useReferencedElements();
    // not a particularly good example but this would animate all referenced
    // item elements and would replay the animation if any of them changed
    useEffect(() => {
        itemElements.forEach(element => element.animate(...));
    }, itemElements);
    return {
        item,
        data
    };
}

// utility function to remove an element from an array
const removeElement = (array, element) => {
    const index = array.indexOf(element);
    if (index < 0) return;
    array.splice(index, 1);
};

Easy access to just a single referenced element

function useForm({ submitForm }) {
    // the return value of useRef can be assigned to an element
    // using the ref attribute
    // its just a special ref handler
    const inputElement = useRef(null);
    // Let's also discuss how to reference an element for reading while
    // binding event handlers
    const buttonElement = useRef(null);
    // but for event handling we really want to leverage the
    // ref handler directly
    const submitButton = useCallback(element => {
        // just store the current element
        buttonElement.current = element;
        return fromEvent(element, 'click').subscribe(() => {
            submitForm({ text: inputElement.value });
        }).add(
            // Rx allows to add teardown logic to an existing subscription
            () => buttonElement.current = null
        );
    }, [submitForm]);
    return {
        inputElement,
        submitButton
    };
}
PrevioususeEffectNextuseCallback

Last updated 6 years ago

Was this helpful?