choojs / nanocomponent

🚃 - create performant HTML components
https://leaflet.choo.io/
MIT License
366 stars 30 forks source link

Render [question] #9

Closed alterx closed 7 years ago

alterx commented 7 years ago

I'm creating a couple of adapters (for Custom Element API v2 and Angular (2+)) and while looking at the code of nanocomponent I could only find one place in which render is called:

if (!isRendered) {
      isRendered = true
      args = _args
      element = render.apply(render, args)
      onload(element, handleLoad, handleUnload)
}

Once this happens, it seems like it's impossible to re render the component. Does this mean that the only way to re-render is to actually remove the node and create a new one? In that case, why do we need the onupdate callback? It looks like there's no way to re-render the component with the updated values (if there is, I'd like to know, maybe I just missed it :D)

Of course we could just do:

onupdate: function (el, args) {
    console.log(`totally updating now`);
    this.apply(this, [args]);
},

since we call update with render as the first parameter of the apply fn. But it wouldn't really help since we can't do anything with the returned node.

I guess my question is, is there a way to re-render the same instance with the updated values, other than re creating the component?

yoshuawuyts commented 7 years ago

Yeah, keep a reference to the rendered element inside the closure and use onupdate to modify its values

On Tue, Feb 14, 2017, 05:30 Carlos Vega notifications@github.com wrote:

I'm creating a couple of adapters (for Custom Element API v2 and Angular (2+)) and while looking at the code of nanocomponent I could only find one place in which render is called:

if (!isRendered) { isRendered = true args = _args element = render.apply(render, args) onload(element, handleLoad, handleUnload) }

Once this happens, it seems like it's impossible to re render the component. Does this mean that the only way to re-render is to actually remove the node and create a new one? In that case, why do we need the onupdate callback? It looks like there's no way to re-render the component with the updated values (if there is, I'd like to know, maybe I just missed it :D)

Of course we could just do:

onupdate: function (el, args) { console.log(totally updating now); this.apply(this, [args]); },

since we call update with render as the first parameter of the apply fn. But it wouldn't really help since we can't do anything with the returned node.

I guess my question is, is there a way to re-render the same instance with the updated values, other than re creating the component?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/yoshuawuyts/nanocomponent/issues/9, or mute the thread https://github.com/notifications/unsubscribe-auth/ACWlejTQXKZBVIpGOS1anqsxnjLTvz4Nks5rcS3ngaJpZM4MADJb .

alterx commented 7 years ago

Interesting, yeah. Tried something like this:

const widgetElement = component({
  onload: function (el) {
    console.log('totally loaded now');
  },
  onunload: function (el) {
    console.log('no more free lunch');
  },
  onupdate: function (el, args) {
    console.log(`totally updating now`);
    el = this.apply(this, [args]);
  },
  render: function (state) {
    return html`
      <p>${state.title}</p>
    `;
  }
});

Update gets triggered with a new title, so that's cool but I get the proxied empty div. I know that I could just update the textNode or appendChild but it just feels like it'd be more natural if you could call render with new args and get the instance updated.

Right now, it's just one node but think about bigger, more complex elements. Is still the textNode approach feasible?

yoshuawuyts commented 7 years ago

you should never do this.apply - instead take the el returned by onupdate and modify its content. You can use whatever you like for that, but personally I prefer morphdom / nanomorph

On Tue, Feb 14, 2017 at 3:29 PM Carlos Vega notifications@github.com wrote:

Interesting, yeah. Tried something like this:

const widgetElement = component({ onload: function (el) { console.log('totally loaded now'); }, onunload: function (el) { console.log('no more free lunch'); }, onupdate: function (el, args) { console.log(totally updating now); el = this.apply(this, [args]); }, render: function (state) { return html`

${state.title}

`;

} });

Update gets triggered with a new title, so that's cool but I get the proxied empty div. I know that I could just update the textNode or appendChild but it just feels like it'd be more natural if you could call render with new args and get the instance updated.

Right now, it's just one node but think about bigger, more complex elements. Is still the textNode approach feasible?

— You are receiving this because you commented.

Reply to this email directly, view it on GitHub https://github.com/yoshuawuyts/nanocomponent/issues/9#issuecomment-279721592, or mute the thread https://github.com/notifications/unsubscribe-auth/ACWlehB1hz6XKw-_ZWR-SOWoFdZ8fgmTks5rcbpLgaJpZM4MADJb .

alterx commented 7 years ago

Yeah, it's not a good idea, just wanted to illustrate there's a way to call render (no the right way, tho) So the suggested way is to modify the element. Perfect, just wanted to have a clear idea of that :)

Closing this one.