How can I react to changes in the window size in SolidJS?

1.6k Views Asked by At

Simple question. How can I react to changes in the window size in solid-js? I need to do some computations with document.body.clientWidth, but I can't get anything to re-execute when that changes. I've tried using on(), memos, functions that are not memos, and the value directly. Nothing's working. There's got to be something simple that I'm missing.

2

There are 2 best solutions below

2
On BEST ANSWER

Solid components can react to signal changes only and reaction is limited to a tracking scope, meaning you can not detect changes outside a computation created by functions like createComputed, createEffect etc.

Now to answer your question, you are trying to react changes that occur outside solid's realm, an outside object that exists and changes on its own. So you need to set a listener on that object, in your case resize event on the window object, and update your signal whenever you receive a resize event:

import { createSignal, onCleanup, onMount } from 'solid-js';
import { render } from 'solid-js/web';

export const App = () => {
  const [rect, setRect] = createSignal({
    height: window.innerHeight,
    width: window.innerWidth
  });

  const handler = (event: Event) => {
    setRect({ height: window.innerHeight, width: window.innerWidth });
  };

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

  onCleanup(() => {
    window.removeEventListener('resize', handler);
  })

  return (
    <div>Window Dimensions: {JSON.stringify(rect())}</div>
  );
};

render(() => <App />, document.body);

Here, we did set listener when component mounts and cleaned up when the component unmounts.

Here you can find a live demo. Try resizing the output frame: https://playground.solidjs.com/anonymous/66ab1288-732e-4847-a0a4-86b8d24af55e

0
On

This answer was originally posted for React (found here) and I just applied it for Solid. What's great about this is that it avoids the window is not defined issue that you'll run into with server side rendering.

import { createEffect, createSignal } from "solid-js";

const useDeviceSize = () => {
    const [width, setWidth] = createSignal(0)
  const [height, setHeight] = createSignal(0)

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

    createEffect(() => {
        // component is mounted and window is available
        handleWindowResize();

        window.addEventListener('resize', handleWindowResize);

    // unsubscribe from the event on component unmount
    return () => window.removeEventListener('resize', handleWindowResize);
    });

    return { width, height };
}

export default useDeviceSize;