milomg / reactively

MIT License
441 stars 23 forks source link

Use Reactively in Solid? #11

Closed joshpoll closed 1 year ago

joshpoll commented 1 year ago

Hi, I really like this library! core is really straightforward and seems easy to hack on.

I'm writing an application in Solid that exposes reactivity to end-users. I want to use reactively instead of Solid's own signals for this, because I need to modify the reactive system to e.g. expose the CacheState so I can present the status of a reactive cell in the UI.

But when I try to naively use reactively like Solid's own signals, things don't update correctly since it's not tied to Solid's reactive system.

import { createSignal } from "solid-js";
import { reactive } from "./reactively";

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

  const countReactively = reactive(0);

  return (
    <div>
      // updates properly
      <h1>Solid Signals</h1>
      <p>You clicked {count()} times</p>
      <button onClick={() => setCount(count() + 1)}>Click me</button>

      // doesn't update :(
      <h1>Reactively Signals</h1>
      <p>You clicked {countReactively.get()} times</p>
      <button onClick={() => countReactively.set(countReactively.get() + 1)}>
        Click me
      </button>
    </div>
  );
}

I'd really appreciate any pointers!

Thanks in advance.

milomg commented 1 year ago

The easiest way to connect the two is to create a reactively effect that writes to a solid signal, which is also how the solid from utility works (https://www.solidjs.com/docs/latest/api#from).

import { createSignal } from "solid-js";
import { reactive, Reactive, stabilize } from "./reactively";

export function TestReactively() {

  const countReactively = reactive(0);

  const [count, setCount] = createSignal(0);
  new Reactive(() => setCount(countReactively.get()), true);

  return (
    <div>
      <h1>Reactively Signals</h1>
      <p>You clicked {count()} times</p>
      <button onClick={() => {
        countReactively.set(countReactively.get() + 1)
        stabilize();
      }>
        Click me
      </button>
    </div>
  );
}
joshpoll commented 1 year ago

Thanks! That's super helpful. Based on that, the solution I'm settling on for now is this:

const fromReactively = <T,>(r: Reactive<any>) =>
  from<T>((set) => {
    reactive(() => {
      set(r.get());
    }, true);
    return () => {};
  });

(not totally sure how to type r)

where I've made the auto-stabilize modifications from #10.