Better way of reusing event listeners for hooks

I have a hook for the window size.
import { Accessor, onCleanup, onMount } from 'solid-js';
import { createSignal } from 'solid-js';

export const useWindowSize = (): {
width: Accessor<number>;
height: Accessor<number>;
} => {
const [width, setWidth] = createSignal(0);
const [height, setHeight] = createSignal(0);

const handle = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
};

onMount(() => {
window.addEventListener('resize', handle);
handle();
});

onCleanup(() => window.removeEventListener('resize', handle))

return { width, height };
}
import { Accessor, onCleanup, onMount } from 'solid-js';
import { createSignal } from 'solid-js';

export const useWindowSize = (): {
width: Accessor<number>;
height: Accessor<number>;
} => {
const [width, setWidth] = createSignal(0);
const [height, setHeight] = createSignal(0);

const handle = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
};

onMount(() => {
window.addEventListener('resize', handle);
handle();
});

onCleanup(() => window.removeEventListener('resize', handle))

return { width, height };
}
It works great, but I want to reuse my event listener because I'll be using this hook in many components. I can always do something like below, but there has to be a better way to do it with something that SolidJS provids? Or even JS.
import { Accessor, onCleanup, onMount } from 'solid-js';
import { createSignal } from 'solid-js';

type Callback = (width: number, height: number) => void;

const cbMap: {[key: string]: Callback} = {};

const handleEvent = () => {
let w = window.innerWidth;
let h = window.innerHeight;
Object.values(cbMap).forEach(cb => cb(w, h));
}

window.addEventListener('resize', handleEvent);

const sub = (uuid: string, cb: Callback) => {
cbMap[uuid] = cb;
return uuid;
}

const unsub = (uuid: string) => {
delete cbMap[uuid];
}

export const useWindowSize = (): {
width: Accessor<number>;
height: Accessor<number>;
} => {
const [width, setWidth] = createSignal(window.innerWidth);
const [height, setHeight] = createSignal(window.innerHeight);
var uuid = crypto.randomUUID();

const handle = (w: number, h: number) => {
setWidth(w);
setHeight(h);
};

onMount(() => {
sub(uuid, handle);
});

onCleanup(() => unsub(uuid))

return { width, height };
}
import { Accessor, onCleanup, onMount } from 'solid-js';
import { createSignal } from 'solid-js';

type Callback = (width: number, height: number) => void;

const cbMap: {[key: string]: Callback} = {};

const handleEvent = () => {
let w = window.innerWidth;
let h = window.innerHeight;
Object.values(cbMap).forEach(cb => cb(w, h));
}

window.addEventListener('resize', handleEvent);

const sub = (uuid: string, cb: Callback) => {
cbMap[uuid] = cb;
return uuid;
}

const unsub = (uuid: string) => {
delete cbMap[uuid];
}

export const useWindowSize = (): {
width: Accessor<number>;
height: Accessor<number>;
} => {
const [width, setWidth] = createSignal(window.innerWidth);
const [height, setHeight] = createSignal(window.innerHeight);
var uuid = crypto.randomUUID();

const handle = (w: number, h: number) => {
setWidth(w);
setHeight(h);
};

onMount(() => {
sub(uuid, handle);
});

onCleanup(() => unsub(uuid))

return { width, height };
}
3 Replies
lxsmnsyc
lxsmnsyc2y ago
tbf though the first one is good enough. I don't see why you should optimize.
FutureLights
FutureLights2y ago
Your probably right. It is much more concise and readable.
Some Call Me Tim
I have a global monitor for window size that's used by all sorts of stuff. I didn't want to add potentially dozens/hundreds of eventListeners onto the Window, so I've got a single use of your first example in a store component which delivers a reactive object of {w:number, h:number} almost globally via context.