Live-signals - LiveState backed signals for all of your signal needs (Phoenix Channels + Signals = LiveSignals)

Hey everybody, it seems like Signals are really catching on as a standard for reactivity in the front end space. Pretty much all the front end frameworks are adopting them, and they are also starting to make their way through the TC39 standards process. As an experiment, I decided to see how easy it would be to connect signals to a Pheonix Channel. Spoiler alert: it was really easy! I used LiveState (a thing I built) to hold the state for the signal.

The resulting library is: GitHub - launchscout/live-signals: LiveState backed signals for all of your signal needs

So far, preact signals and the TC39 polyfill are supported, but adding additional signal implementations should be trivial PRs I would be delighted to receive and merge :wink:

As always, feedback is welcomed :slight_smile:

14 Likes

This topic is a pure announcement. For Elixir or Phoenix it’s not a problem, but in this case lots of people may have no idea what Signals are. If you are one of them take a look at this article:

6 Likes

Just looked at the code.
As it is for preact I do not really understand whats going on.

So just that we are on the same page, this is a basic example from the solidjs tutorial

function Counter() {
  const [count, setCount] = createSignal(0);

  setInterval(() => setCount(count() + 1), 1000);

  return <div>Count: {count()}</div>;
}

createSignal() returns a [getter, setter], the setter is being used in the interval to count up, the getter is used in the JSX. The reactive system will now change exatly that number directly in the DOM and nothing else on each change of count().

What would live-signals do now with this?
Do I transparently get “subscribe” to the signal on the server and vice-versa?

What about stores? (A Comprehensive Guide to SolidJS Stores - Raqueebuddin Aziz)
While signals (at least in solid) are mainly used for view-stuff, stores are where the state is, so that would be really nice to get access to from the server.

Hey Sebb,

From the example, my first thought is that adding support for SolidJS, at least initially, would work in a very similar way to the preact and polyfill versions: with a createSolidSignal that returns an array of [signal, dispatchEvent]. If it’s as trivial to build an example with Solid as it was with Preact (which I have pretty much zero experience with) it should be really easy to do.

Still do not really understand what it does, do you have an example?

I don’t think it’s a complete example (as onInput and onClick don’t seem to be used) but I think onClick in the following:

Shows how you can trigger events on the server:

Presumably, the state of the signal client-side will reflect what the server sent it, and the client uses dispatchEvent to call those server-side handlers.

1 Like

Yup that’s pretty much it. I’ll see if I can do a more complete example later this week. If I really get ambitious I’ll do a solid example as well.

I get how this works now.

But do you really think its feasible to share state between client and server using signals?
Sth that can do that with stores would be great.

There is prior art with Storex - Frontend store with the state on the backend which is cool and works well but is kind of limited as it relies on some kind of subscriber interface, like solid’s from.

I’ve added a little more to the preact example now. It’s not as fleshed out as the live-templates example I copied it from, but it works as far as showing how to dispatch event. Note that I have really know idea what I’m doing with Preact, so there is likely I more ideomatic preact approach. To your question @Sebb , as it seems like Signals are getting a reasonable amount of traction, using them to re-render state updates pushed down over a Phoenix Channel seems to be viable AFAICT. It really doesn’t change much: we are doing much the same with Lit Element based apps without signals, and it’s worked well for us.

1 Like

Makes sense. This will work fine for a handful of components.

What I have in mind right now is keeping the state on the server and have hundreds of components use that state. That may get messy using signals.

Or how would you do sth like this (client side pseudo code)

for component in 1..1000 do
   <component /> <-- this creates a signal that wants to talk to the server
end

SolidJS’ createStore will create sth like this

[store, setStore] = getProxies(createSignal([
  getProxies(createSignal(<element_0_initial>)),
  getProxies(createSignal(<element_1_initial>)),
  ...
]))

for createStore([<element_0_initial>, ..])

So its easy to handle more complex state, but not trivial to share with the server I think.

Sorry for getting offtopic, this is about signals and will do a fine job if that’s what needed

Maybe this is my lack of understanding of signals, but what do they add in an ecosystem with LiveView, processes and messages being passes around?

Say you implemented a webcomponent like

// this will tick up each second
customElement('my-counter', () => {
  const [count, setCount] = createSignal(0);
  setInterval(() => setCount(count() + 1), 1000);
  return <div>Count: {count()}</div>;
})

and use this in your LV like

<my-counter id="counter_1"></my-counter>

You could just handle the state of the counter in LV-handle_info, or overwrite the count from the server. Without a bridge for the signals, you’d have to do that manually using events and hooks or such.

1 Like

Oh, so it is for webcomponents.
Gotcha, thanks!

1 Like

This library is designed to help with front end frameworks that use Signals, such as Preact and eventually other signal embracing libraries such as Solid, Svelte, etc, etc. It can also be used by web components, but LiveState already has very nice support for web components without needing signals.

However, all of these options (and LiveState in general) are designed to help you when, for whatever reason, LiveView is not a good option. Integrating LiveView itself with front end frameworks is whole separate topic and something you probably don’t want to try to do unless you really, really have to :slight_smile:

1 Like

Yeah, it sounds like you may want something specific for Solid to create a store backed by a LiveState channel. LiveSolid or some such thing? My guess, based on experience so far, is that you could use LiveSignals as an example and create such a thing in just few lines of code.

Why not unify to live state?

LiveSignals is a library that builds on top of LiveState. Not sure what you asking