IvonaK
IvonaK

Reputation: 288

How to use Preact signals with astro to share state

Problem When i change the tag value it only changes on the select component but not in the index.astro

I have folder signals where i export signal

export const tagSignal = signal<string>("all");

I use it like this in Select.tsx component, and here evryting changes

import { tagSignal } from "@signal/*";
const setTagValue = (value: string) => {
  tagSignal.value = value;
  console.log("select", tagSignal.value);
};

export const Select = () => {
  const [display, setDisplay] = useState(false);
  const [selectedName, setSelectedName] = useState("all"); // this will be change to only signals still under refator
  setTagValue(selectedName);
 -------
 ------

but when I import it to index.astro like this I get only "all" value witch is inital value

---
import { Icon } from "astro-icon";
import { Picture } from "astro-imagetools/components";

import Layout from "@layouts/Layout.astro";
import { Select } from "@components/Select";
import Card from "@components/Card.astro";

import { getCollection } from "astro:content";
import { getProjectsByTag } from "@utils/*";
import { tagSignal } from "@signal/*";

const projects = await getCollection("projects");

const filteredProjects = getProjectsByTag(projects, tagSignal.value);
// TODO: add links

console.log("index", tagSignal.value);
---
/// some code here
 <section id="projects" class="projects">
      <Select client:only="preact" />
      <div class="projects-wrapper">
        {
          filteredProjects.map(({ data: { title, heroImage } }) => (
            <Card name={title} bg_path={heroImage} />
          ))
        }
      </div>
    </section>
---

Upvotes: 1

Views: 1129

Answers (1)

HynekS
HynekS

Reputation: 3317

I see two issues here.

  1. You are depending on dynamic JS variables in an .astro file. It doesn't work the way you are expecting—all the javascript in .astro files, with the exception of the "islands," e.g., your Select.tsx component, is being evaluated when the page is being built. So Astro grabs the initial value of tagSignal, but makes it a static string.

People can get bitten by, e.g., the trivial ©2010—{new Date().getFullYear()} in the footer – it won't magically update on the new year's eve if used in .astro file.

  1. The state (signal's current value) is not shared accross the islands. If you want to share it, you need either a global state solution (I haven't used it in Astro yet), or just create a common parent for the Select and the filtering logic, e.g.:
{/* the signal will be declared (or imported) in `DynamicSection`*/}
<DynamicSection client:only="preact">
    <Select />
    <div class="projects-wrapper">
      {
        filteredProjects.map(({ data: { title, heroImage } }) => (
          <Card name={title} bg_path={heroImage} />
        ))
      }
    </div>
</ DynamicSection>

(The simplest global state solution would be probably using the url with a query string, and derive the state from its value).

Upvotes: 0

Related Questions