The entire component is being re-rendered when using signals

Why is my entire component being re-rendered, even though I’m using the new “signals” library? What am I doing wrong? Only the button is supposed to be re-rendered, not the entire component.

NOTE: I used the Preact Developer Tools to test the component with the option “Highlight updates” activated. This shows the parts of the component that is being re-rendered.

Here’s the code:

import { useSignal } from "@preact/signals";

export function Home() {
  const toggle = useSignal(false);

  return (
    <div>
      <button onClick={() => (toggle.value = !toggle.value)}>
        {toggle.value ? "yes" : "no"}
      </button>
      <p>This is re-rendered every time 'toggle.value' changes.</p>
    </div>
  );
}

To take advantage of the rendering optimizations, you need to use the signal directly in your component; unwrapping with .value disables this. Docs

If you want to display different text based upon the signal value, your best bet would be to add a computed in:

import { useSignal, useComputed } from "@preact/signals";

export function Home() {
  const toggle = useSignal(false);
  const toggled = useComputed(() => (toggle.value ? "yes" : "no"));

  return (
    <div>
      <button onClick={() => (toggle.value = !toggle.value)}>
        {toggled}
      </button>
      <p>This is re-rendered every time 'toggle.value' changes.</p>
    </div>
  );
}

Note: it’s generally better to use the non-hook functions (signal and computed vs useSignal and useComputed) if at all possible.

Leave a Comment