HOAB

History of a bug

React and events

Rédigé par gorki Aucun commentaire

Problème :

J'utilise React pour développer une application frontend et j'utilise les méthodes de base Javascsript pour gérer les événements venant du serveur ou en interne Front.

J'ai trouvé sur internet quelques fonctions utiles pour gérer les événements (je n'ai pas retrouvé où !) :

  • on : abonnement
  • off : désabonnement
  • trigger : déclencher un évenement

Pour mon usage, j'ai customisé ces fonctions en ajoutant une callback en paramètre. Résultat j'ai ce code : 

function on(eventType:string, state:any, listener:(detail:MyEvent) => void) {
    const resultFunction = function(event:any) {
        listener(event.detail)
    };
    document.addEventListener(eventType, resultFunction);

Cela me permet de gérer des événements qui héritent de MyEvent.

Le problème est que, ce faisant, je crée une fonction anonyme à chaque souscription et que du coup il est impossible d'utiliser removeEventListener lorsque le composant se démonte.

Solution :

Indirectement c'est ce guide qui m'a aidé : https://dev.to/marcostreng/how-to-really-remove-eventlisteners-in-react-3och

L'idée était donc bien de garder la référence à la fonction anonyme créée (qui me permet de gérer des callbacks génériques), mais comment simplifier l'usage pour éviter de devoir faire stocker la référence à cette fonction anonyme par tous les composants ?

Eh bien en la stockant moi-même directement dans le state !

Sur le désabonnement, je vais chercher dans le state, la référence à la fonction anonyme stockée pour mon type d'événement.


function buildKey(eventType: string) {
    return 'clientside-events.listener.' + eventType;
}

function on(eventType:string, state:any, listener:(detail:MyEvent) => void) {
    const resultFunction = function(event:any) {
        listener(event.detail)
    };
    document.addEventListener(eventType, resultFunction);
    if (state !== null) {
        if (!state.listeners) {
            state.listeners = new Map();
        }
        state.listeners.set(buildKey(eventType), resultFunction);
    }
    return resultFunction;
}

function off(eventType:string, state:any) {
    if (state !== null && state.listeners) {
        document.removeEventListener(eventType, state.listeners.get(buildKey(eventType)));
    } else {
        console.warn('Trying to remove a listener but not found for ' + eventType)
    }
}

function trigger(eventType:string, message:ShaanEvent) {
    const event = new CustomEvent(eventType, { detail: message });
    document.dispatchEvent(event);
}

export { on, off, trigger };

 

Fil RSS des articles de ce mot clé