preactjs / signals

Manage state with style in every framework
https://preactjs.com/blog/introducing-signals/
MIT License
3.63k stars 88 forks source link

My component doesn't rerender when the signal value change... #480

Closed ElBaDaNoS closed 6 months ago

ElBaDaNoS commented 6 months ago

Environment:

React version: 18.2.0 @preact/signals-react version: 2.0.0 Issue Description: The collapsed signal from @preact/signals-react is not causing visual updates in the sidebar component when its value is toggled via a button click. There is no change in the sidebar's width or the toggle icon's shape upon the click event. Interestingly, the collapsed.value only updates in the console log after the component files are saved in VSCode without any actual code changes.

Steps to Reproduce:

Define a collapsed signal with @preact/signals-react. Bind the signal to a className that conditionally sets the sidebar's width. Implement a button that toggles the collapsed signal's value. Expected Behavior: Clicking the button should collapse or expand the sidebar, and the toggle icon should change shape, reflecting the collapsed signal's value.

Actual Behavior: The sidebar does not change its width, nor does the toggle icon change shape upon interaction. Strangely, when the related source files are saved in VSCode without any modifications, the expected behavior is momentarily triggered.

Additional Context: This inconsistent behavior suggests a potential issue with how state persistence or HMR (Hot Module Replacement) is handled in the development environment.

Here is my code for the SideBar component:

import React from "react";
import { collapsed } from "../Signals/Collapsed";
import { Link } from "react-router-dom";
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "./ui/accordion";
import { buttonVariants } from "./ui/button";
import { Bell, Book, FileSignature, Search } from "lucide-react";
import { Input } from "./ui/input";

// Sidebar component
const Sidebar: React.FC = () => {
  console.log(collapsed.value);
  // State to handle the collapse of the sidebar

  return (
    <aside
      className={`transition-all duration-300 ${
        collapsed.value ? "w-16" : "w-64"
      } h-full border-b border-gray-200 bg-slate-300 backdrop-blur-lg transition-all`}
    >
      <div className="flex items-center rounded w-[93.75%] py-2">
        <div className="border-r px-2 flex items-center justify-center">
          <Search className="h-5 w-5 text-zinc-600" />
        </div>
        <Input
          type="text"
          className="flex-1 px-4 py-2 w-full rounded-r"
          placeholder="Search..."
        />
      </div>
      <div className="flex gap-8 justify-center py-2">
        <div className="flex items-center gap-2 text-zinc-600">
          <span className="text-sm font-semibold">2</span>
          <Book className="w-4 h-4 text-zinc-600" />
        </div>
        <div className="flex items-center gap-2 text-zinc-600">
          <span className="text-sm font-semibold">2</span>
          <FileSignature className="w-4 h-4 text-zinc-600" />
        </div>
        <div className="flex items-center">
          <Bell className="w-4 h-4 text-zinc-600" />
        </div>
      </div>
      <nav>
        {/* Library of Minute Books */}
        <Accordion type="multiple" className="px-2 w-[93.75%]">
          <AccordionItem value="item-1">
            <AccordionTrigger className="items-center">
              Library section
            </AccordionTrigger>
            <AccordionContent>
              {" "}
              <div
                className={buttonVariants({
                  variant: "ghost",
                  size: "sm",
                  className: "hover:bg-slate-400",
                })}
              >
                Minute Books
              </div>
            </AccordionContent>
            <AccordionContent>
              <div
                className={buttonVariants({
                  variant: "ghost",
                  size: "sm",
                  className: "hover:bg-slate-400",
                })}
              >
                Trusts
              </div>
            </AccordionContent>
            <AccordionContent>
              {" "}
              <div
                className={buttonVariants({
                  variant: "ghost",
                  size: "sm",
                  className: "hover:bg-slate-400",
                })}
              >
                Other Regimes
              </div>
            </AccordionContent>
            <AccordionContent>
              <AccordionItem value="item-2" className="border-none">
                <AccordionTrigger className="items-center">
                  Specialized Sections
                </AccordionTrigger>
                <AccordionContent>
                  <div
                    className={buttonVariants({
                      variant: "ghost",
                      size: "sm",
                      className: "hover:bg-slate-400",
                    })}
                  >
                    Merged Companies
                  </div>
                </AccordionContent>
                <AccordionContent>
                  <div
                    className={buttonVariants({
                      variant: "ghost",
                      size: "sm",
                      className: "hover:bg-slate-400",
                    })}
                  >
                    Dissolved Companies
                  </div>
                </AccordionContent>
                <AccordionContent>
                  <div
                    className={buttonVariants({
                      variant: "ghost",
                      size: "sm",
                      className: "hover:bg-slate-400",
                    })}
                  >
                    Archived Companies
                  </div>
                </AccordionContent>
                <AccordionContent>
                  <div
                    className={buttonVariants({
                      variant: "ghost",
                      size: "sm",
                      className: "hover:bg-slate-400",
                    })}
                  >
                    Extended Companies
                  </div>
                </AccordionContent>
              </AccordionItem>
            </AccordionContent>
          </AccordionItem>
          <AccordionItem value="item-5" className="border-none">
            <AccordionTrigger>Access Control</AccordionTrigger>
            <AccordionContent>
              {" "}
              <Link
                to="/RestrictedAccess"
                className={buttonVariants({
                  variant: "ghost",
                  size: "sm",
                  className: "hover:bg-slate-400",
                })}
              >
                History logs
              </Link>
            </AccordionContent>
            <AccordionContent>
              {" "}
              <Link
                to="/RestrictedAccess"
                className={buttonVariants({
                  variant: "ghost",
                  size: "sm",
                  className: "hover:bg-slate-400",
                })}
              >
                Restricted Access
              </Link>
            </AccordionContent>
          </AccordionItem>
        </Accordion>
      </nav>
    </aside>
  );
};

export default Sidebar;

and here is my code for the ToogleIcon component:

import { Button } from "./ui/button";
import { collapsed } from "../Signals/Collapsed";

const ToogleIcon = () => {
  console.log(collapsed.value);

  const openSidebar = () => {
    collapsed.value = false;
  };

  const closeSidebar = () => {
    collapsed.value = true;
  };

  return collapsed.value ? (
    <div className="w-12 h-full flex items-center justify-center">
      <Button
        variant="ghost"
        className="focus:outline-none focus:shadow-outline rounded-full"
        onClick={() => openSidebar()}
      >
        <div className="flex h-[72px] w-8 items-center justify-center group">
          <div className="flex h-6 w-6 flex-col items-center justify-between">
            <div className="h-3 w-1 bg-zinc-300 transform group-hover:translate-y-1 group-hover:-rotate-45 transition duration-300"></div>
            <div className="h-3 w-1 bg-zinc-300 transform group-hover:translate-y-[-1px] group-hover:rotate-45 transition duration-300"></div>
          </div>
        </div>
      </Button>
    </div>
  ) : (
    <div className="w-12 h-full flex items-center justify-center">
      <Button
        variant="ghost"
        className="focus:outline-none focus:shadow-outline rounded-full"
        onClick={() => closeSidebar()}
      >
        <div className="flex h-[72px] w-8 items-center justify-center group">
          <div className="flex h-6 w-6 flex-col items-center justify-between">
            <div className="h-3 w-1 bg-zinc-300 transform group-hover:translate-y-1 group-hover:rotate-45 transition duration-300"></div>
            <div className="h-3 w-1 bg-zinc-300 transform group-hover:translate-y-[-1px] group-hover:-rotate-45 transition duration-300"></div>
          </div>
        </div>
      </Button>
    </div>
  );
};

export default ToogleIcon;

`

XantreDev commented 6 months ago

Have you followed babel setup instructions? https://github.com/preactjs/signals/tree/main/packages/react#react-integration

rschristian commented 6 months ago

You're not calling useSignals(), so are you using the Babel plugin?

Minimal reproduction please, not a hundred lines of component code.

ElBaDaNoS commented 6 months ago

Have you followed babel setup instructions? https://github.com/preactjs/signals/tree/main/packages/react#react-integration

Indeed, I revisited the Babel setup instructions as you suggested and found that I hadn't properly configured the Babel plugin for Preact signals. After updating my Vite configuration to include the @preact/signals-react-transform plugin within the React plugin's Babel settings, it started working as expected. Here's the snippet I added to vite.config.ts:

plugins: [
  react({
    babel: {
      plugins: [['module:@preact/signals-react-transform']],
    },
  }),
],

This change made my React components correctly respond to signal changes.

Thank you for your help!