My Component
import { h } from 'preact';
import { quoteSignal } from '/quoteStore.ts';
export default function Button() {
return (
<button>hello 1 {quoteSignal.value}</button>
);
}
my signal
import { signal } from '@preact/signals';
// Create a signal for the shared label
export const quoteSignal = signal('first');
My island
import { useEffect } from 'preact/hooks';
import { quoteSignal } from '/quoteStore.ts';
export default function QuoteIsland() {
useEffect(() => {
quoteSignal.value = "Test Label";
console.log("useeffect")
const fetchQuote = async () => {
const response = await fetch('/api/quote/mystock');
const data = await response.json();
console.log(data.price);
quoteSignal.value = data.price;
};
fetchQuote();
const intervalId = setInterval(fetchQuote, 10000); // 10 seconds
return () => clearInterval(intervalId);
}, []);
return null; // This component does not need to render anything
}
Test Label is never displayed, as are none of the updates from api, even though the console log shows them. The button only ever displays as its label "first".
Fresh maintainer here.
To share a signal across or with islands, pass them via props
. Sharing data with islands in other ways like globals is not supported in Fresh.
The reason this doesn't work is that Fresh only runs components on the server by default. When you create an island, we generate a JavaScript bundle that's optimized for the browser. During the bundling process that island is then inlined into the bundle. We then render the HTML on the server, send it to the browser and the browser instantiates the islands by loading the relevant bundles.
The browser has no clue that you used a signal in the Button
component since that was only ever rendered on the server. If Fresh would be a server-only framework that never ran JavaScript in the browser, sharing data via global signals would work.
But the key strength of Fresh is its island architecture which allows you to run JavaScript in the browser for parts of the page that need it. If the Button
component is only ever rendered on the server, then it will never be updated in the browser, regardless of how you passed data to it, like whether it came from a signal or somewhere else. The browser only sees the final HTML rendered by the server and then makes the islands interactive. It has no clue how that HTML was generated or if the resulting HTML of a Button
component had a signal in it.
The boundary as to how data is shared from the server with the browser is through props
of an island. We serialize all props and send it along with the HTML to the browser. Anything not passed via props
of an island will not be shared. And in the browser, the only components that are interactive are islands and components referenced inside of it. Nothing else will be interactive.