pod-os / PodOS

Personal Online Data Operating System
MIT License
13 stars 1 forks source link

Reactivity to state changes #37

Open josephguillaume opened 3 months ago

josephguillaume commented 3 months ago

Opening this issue to document opportunities for components to react to state changes, building on the rxjs decision:

https://github.com/pod-os/PodOS/blob/7d2693a3b47cc3bc837060bc761d5aabf42c2b27/docs/decisions/0009-introduce-rxjs.md?plain=1#L19

By state changes, I firstly have in mind cases where the triples affecting a subject or object change, either because of another component on the same page or due to data changes. The primary use case is to perform reactive rendering. It will likely be desirable to standardise how this is dealt with across solid web components. See https://github.com/solid-contrib/web-components/wiki/Rendering

e.g. pos-label is displaying data from the triple

:subject rdfs:label "subject label".

This triple is then replaced in the store by

:subject rdfs:label "new subject label".

pos-label needs to rerender with the new value

josephguillaume commented 3 months ago

Because PodOs uses rdflib.js, at the moment it is possible for custom components to achieve reactive rendering using callbacks on the graph store.

os.store.graph.addDataCallback(doUiCallbacks);
os.store.graph.rdfArrayRemove = (a, x) => {
    for (var i = 0; i < a.length; i++) {
      if (
        a[i].subject.equals(x.subject) &&
        a[i].predicate.equals(x.predicate) &&
        a[i].object.equals(x.object) &&
        a[i].why.equals(x.why)
      ) {
        doUiCallbacks(x);
        a.splice(i, 1);
        return;
      }
    }
    throw new Error("RDFArrayRemove: Array did not contain " + x + " " + x.why);
  };

doUiCallbacks is called on every triple change. It therefore needs to efficiently manage a set of callbacks to individual custom components as well as throttle repeat callbacks in some way.

I have a basic buggy implementation of this.

josephguillaume commented 3 months ago

Given the decision to use rxjs, it makes sense to revisit this callback architecture and identify a solution better suited to PodOs.

PodOs core encapsulates rdflib.js so that elements do not depend on it ^1

Building on the idea that rxjs provides lazy push collections of multiple values, a possible solution is that the properties of Thing ^2 become observables

e.g. label is no longer a pull function that returns a value, but is instead a push observable that pos-label reacts to. The construction/destruction of a Thing would need to handle subscription to observables, and manage the callbacks from rdflib.js

This would be a major architectural change, which could either be approached as a breaking change, or by PodOS core offering both push and pull architectures for accessing data.

However, for devx reasons, I believe PodOs elements should either all be individually reactive to state or not, and I currently believe that making every web component state-reactive is the preferred option.

Whatever final architecture is used, I have found that retaining low level access to rdflib.js is often needed given PodOs does not fully cover the rdflib.js api. It would therefore be beneficial for the callback management mechanism to be accessible from custom components, even if direct use is discouraged.

There may be other solutions, which is why I've framed this issue as documenting opportunities rather than proposing this as the definitive solution.

josephguillaume commented 2 months ago

As a point of comparison, semantic-ko used observables through the knockoutjs library, though I think PodOS would want to avoid defining an explicit view model.

https://web.archive.org/web/20111118042156/http://antoniogarrote.com/semantic_ko/

josephguillaume commented 2 weeks ago

Noting that while external components will use rxjs, reactivity to logged in state (and Webid, and profile) is still managed using a stenciljs store for image, navigation bar, resource and document, with pos-app providing the bridge between rxjs and the store.

https://github.com/pod-os/PodOS/blob/7d2693a3b47cc3bc837060bc761d5aabf42c2b27/elements/src/store/session.ts

https://github.com/pod-os/PodOS/blob/7d2693a3b47cc3bc837060bc761d5aabf42c2b27/elements/src/components/pos-app/pos-app.tsx#L48