whatwg / dom

DOM Standard
https://dom.spec.whatwg.org/
Other
1.58k stars 295 forks source link

General DOM effect/Object mutation DOM effect #1049

Closed yonathan06 closed 2 years ago

yonathan06 commented 2 years ago

Suggesting to add a basic reactivity method for a DOM element, inspired by the latest (or maybe not so latest) changes in the frameworks/libraries landscape (mainly inspired by solidjs) My suggestion is having a native dom element effect, that can later be extended by libraries (or remove the necessity of complicated reactive libraries)

First proposal

const triggerEffect = domElement.createEffect((value) => {
    // replaces the textContent of the element
    return `Hello ${value}`;
});
//...
triggerEffect("world");

Update - second proposal

const state = domElement.createEffect(function (currentState) {
  this.textContent = `Hello ${currentState.x}`;
}, { x: "Joe" });

state.x = "World";
bathos commented 2 years ago

I’m not sure what the example is showing exactly. It seems like there could be some context missing about what exactly createEffect is meant to do. The comment says “replaces the textContent of the element.” On the surface that sounds like the existing textContent setter:

let triggerEffect = value => domElement.textContent = `Hello ${ value }`;
triggerEffect("world");

Is the function-factory-function-that-accepts-a-function part doing something else besides this?

(...if not, “remove the necessity of complicated reactive libraries” might already be done!)

yonathan06 commented 2 years ago

@bathos you are probably right, and it unnecessary for just textContent (or maybe just a syntactic sugar)

I mentioned it as a textContent change effect only as an idea, but maybe having some reactive primitive in the DOM API could advance the ecosystem.

maybe using an object as a dependency (using Proxy object behind the scenes) This is heavily inspired by Solidjs, as Ryan Carniato using Proxy objects just for that, and I thought "why no having it as part of the DOM API"

const state = domElement.createEffect(function (currentState) {
  this.textContent = `Hello ${currentState.x}`;
}, { x: "Joe" });

state.x = "World";

of course this could be implemented like that:

const state = new Proxy({ x: "Joe" }, {
  set: function (obj, prop, value) {
    obj[prop] = value;
    if (prop === "x") {
      domElement.textContent = `Hello ${value}`;
    }
    return true;
  }
});

state.x = "World";

But I think that the abstraction is needed to hide complexity, and making it more intuitive, closer to how popular reactive libraries are describing reactivity (when something changes, change the view)

bathos commented 2 years ago

A Proxy is not necessary for implementing a single accessor's set function (that's why the “set” handler exists, with a receiver arg, in addition to the more foundational “defineProperty”: it “explains” setter behavior). It is a pretty indirect and expensive way to say the same thing if you already know the key in advance - but in this case, incorrectly, as the resulting object will not satisfy invariants of the meta object protocol. I would advise not using Proxy for things like this.

It may be helpful to explain what problem this seeks to solve.

Edit: revisiting this tab and realized the first part of the response reads way too “didactic” in a bad way, especially given you were likely just stubbing. Unsound proxies in the wild aren’t uncommon so I tend to wave the danger beacon quick now when they come up, but of course I love em too :)

yonathan06 commented 2 years ago

Thanks @bathos for the detailed comment, I do try to refine the idea:

I'm not suggesting a new feature that will introduce a new capability that can not be solved with a workaround, my idea is to have some primitive function that allows reactive DOM change based on an object mutation (or something on this direction). The reason for it is that almost every reactive library (react, vue, svelte, solidjs...) are based on the fundamental idea of having a declarative code that says "when this value changes, the view should change with the value", so I thought why not having it "baked in" the DOM API, or at least a primitive version of it (of course there is always a room for libraries to provide more abstraction, but having a DOM function that updates the element's content/attribute when data changes can push those technologies forward)

pshaughn commented 2 years ago

This sounds a lot like MutationObservers, but 'owned' by the node they're observing instead of having a separate lifecycle?

bathos commented 2 years ago

If I understood @yonathan06 right, the idea wasn’t to observe DOM mutation, but rather to associate DOM mutation side effects with property assignment. Though the first example didn’t include the property assignment part.

There is a pretty well-proven need for more efficient templating primitives I think. This is where the (necessary) complexity in templating libraries tends to live today, so “textContent” might be too optimistic of an example. A solid model for updateable HTML template “substitution nodes” that can handle things like array mapping without every framework needing to reimplement it has probably got to come before novel surface API can be built on top.

Fortunately it seems like there’s been a fair amount of exploratory work on that front (referred to as “template instantiation” or “template parts”). It’s a pretty big lift though and I’m not sure what its current state is. It seemed like both Apple and Google were invested in pursuing its development. If it succeeds, it could be what provides that missing “update-by-value” layer, so if one’s preferred programming paradigm seems to be at odds with JS / the web platform, there’d only be a thin layer needed to map over to it.

I was looking at solidjs a bit and realized this discussion might concern “hooks” rather than just reactivity. Is that the case? (I’m not sure — but it might help explain the first example.) If that is the case: I think it’s unlikely that a platform API that promotes or facilitates it would fly, at least not as it gets realized today. It’s very creative, but reinventing undefined behavior & memory unsafety over a language whose actual semantics exhibit neither is not exactly universally accepted as the future :) JS could one day introduce features that allow patterns of that sort to be realized safely, but till then, the linter-acting-as-a-compiler that enforces the boundaries of the overlaid semantics during dev just wouldn’t be there in the browser, so you’d always be one if statement away from chaos.

Jamesernator commented 2 years ago

I haven't seen any work done on it in a long time, but the DOM parts proposal was supposed to provide access into areas of DOM such that content could be updated fairly directly.

However I don't know if implementers are still looking to pursue that as I have seen limited activity on any host work on such features.

yonathan06 commented 2 years ago

@bathos You are right, the idea is binding object changes to DOM manipulation. I updated the issue description to include the second example.

I believe that until a cohesive templating functionality will be introduced, having simple and less opinionated primitive solution, that can be expended later by libraries, or used as is in simple cases (static pages that require minimal functionality) will push the ecosystem a big step forward. I'll take your words regarding JS runtime, maybe a deeper thought on how the engine should optimize and make it memory safe is needed. Many web apps (that are using a certain library/framework) use a model->view pattern, as it best describes the intention, and I think having a descriptive functionality is needed so people won't have to reinvent the wheel with every library, but use the standards provided by the runtime.

bathos commented 2 years ago

I haven't seen any work done on it in a long time, but the DOM parts proposal was supposed to provide access into areas of DOM such that content could be updated fairly directly.

@Jamesernator that’s what I was thinking of earlier. I’d thought I’d seen relatively recent threads about it but maybe those were older discussions than I’d realized. It seemed like a pretty strong starting point at the least, so seems a bit sad to hear it’s not moving.

Many web apps (that are using a certain library/framework) use a model->view pattern, as it best describes the intention, and I think having a descriptive functionality is needed so people won't have to reinvent the wheel with every library, but use the standards provided by the runtime.

I think that makes sense, too. I suppose I think the work to get there mostly lives in a different place, but I don’t mean to discourage the investigation or anything.

Shar65 commented 2 years ago

Seeing as though I have to be in the same area as you, and live with you it’s not going to work cuz I can’t be there 

Sent from Yahoo Mail for iPhone

On Monday, January 31, 2022, 1:39 PM, Darien Maillet Valentine @.***> wrote:

I haven't seen any work done on it in a long time, but the DOM parts proposal was supposed to provide access into areas of DOM such that content could be updated fairly directly.

@Jamesernator that’s what I was thinking of, earlier. I’d thought I’d see relatively threads on it but maybe I was reading older stuff than I realized. It seemed like a pretty strong starting point at the least, so seems a bit sad to hear it’s not moving.

Many web apps (that are using a certain library/framework) use a model->view pattern, as it best describes the intention, and I think having a descriptive functionality is needed so people won't have to reinvent the wheel with every library, but use the standards provided by the runtime.

I think that makes sense, too. I suppose I think the work to get there mostly lives in a different place, but I don’t mean to discourage the investigation or anything.

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you are subscribed to this thread.Message ID: @.***>