danculley / real-dom

A ~1K non-virtual DOM non-framework framework for simple apps
36 stars 2 forks source link

Lifecycles methods #2

Open IamCarbonMan opened 7 years ago

IamCarbonMan commented 7 years ago

While I don't really care about having feature parity with React, its lifecycle methods are very useful. Could we get these in real-dom?

danculley commented 7 years ago

Can you provide more details about what you are trying to do? Since the entire set of DOM nodes underneath the application root is destroyed and then recreated each time that the dispatch method is called, I'm not sure many of them would make sense. But it might be clearer once I have a better understanding of your goal.

IamCarbonMan commented 7 years ago

I think just "mount", "remount", and "unmount" would be sufficient. Currently I only really need "remount" to build an auto-scrolling-to-bottom list (ie, a chat widget), but "mount" is basically the same thing as registerSubscriptions, and "unmount" would be for cleanup when an element is no longer used. Of course, there currently isn't a mechanism for unmounting a component, but I think there should be.

danculley commented 7 years ago

I've been giving some thought to this. The point of the library of course is to avoid replicating things that the DOM already does. But there are of course ergonmics that make it difficult, which is why I did this in the first place.

In terms of unmounting, my view is that the right place to do cleanup is in an 'beforeunload' event handler placed on window object in the registerSubscriptions function. That feels right to me, and you will generally want access through a closure to everything you are setting up in registerSubscriptions when you are tearing things down in any case.

In terms of being being "re-mounted", since there are actual DOM nodes being handled in the view function, you can use the DOM methods to let you know when the node you are returning has actually been added to the document, though it is a bit clunky. (It is amazing that there isn't a simple event fired on a DOM Node when it is added to a document, at least that I'm aware of. See a wrapper function below that returns a promise that resolves when the DOM node has been added to the document.) That feels too difficult to me, but I need to think about the best way to do it. Maybe it would just be making this utility function available in the library. Not sure.

Wrapper function:

const ready = node => new Promise((resolve, reject) => {
  const check = () => {
    const isReady = document.body.contains(node);
    if (isReady)
      resolve(node);
    return isReady;
  }
  const mo = new MutationObserver(() => {
    if (check())
      mo.disconnect();
  });
  mo.observe(document.body, {childList:true, subtree:true});
})

And then you would use it in your view function like so:

(state, dispatch) => {
  const element = h('ol', {}, state.messages.map(message => h('li', {}, `{message.sender} ({message.time}): {message.text}`));
  ready(element).then(element => element.scrollTop = element.scrollHeight);
  return element;
}
IamCarbonMan commented 7 years ago

This definitely works for the scope of this project. I really would love to see something with API parity with React, but using the real DOM. But having been using real-dom in a few projects for a while now, I'm getting more used to the "bare metal" approach.

On Mar 30, 2017 13:39, "danculley" notifications@github.com wrote:

I've been giving some thought to this. The point of the library of course is to avoid replicating things that the DOM already does. But there are of course ergonmics that make it difficult, which is why I did this in the first place.

In terms of unmounting, my view is that the right place to do cleanup is in an 'beforeunload' event handler placed on window object in the registerSubscriptions function. That feels right to me, and you will generally want access through a closure to everything you are setting up in registerSubscriptions when you are tearing things down in any case.

In terms of being being "re-mounted", since there are actual DOM nodes being handled in the view function, you can use the DOM methods to let you know when the node you are returning has actually been added to the document, though it is a bit clunky. (It is amazing that there isn't a simple event fired on a DOM Node when it is added to a document, at least that I'm aware of. See a wrapper function below that returns a promise that resolves when the DOM node has been added to the document.) That feels too difficult to me, but I need to think about the best way to do it. Maybe it would just be making this utility function available in the library. Not sure.

Wrapper function:

const ready = node => new Promise((resolve, reject) => { const check = () => { const isReady = document.body.contains(node); if (isReady) resolve(node); return isReady; } const mo = new MutationObserver(() => { if (check()) mo.disconnect(); }); mo.observe(document.body, {childList:true, subtree:true}); })

And then you would use it in your view function like so:

(state, dispatch) => { const element = h('ol', {}, state.messages.map(message => h('li', {}, {message.sender} ({message.time}): {message.text})); ready(element).then(element => element.scrollTop = element.scrollHeight); return element; }

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/danculley/real-dom/issues/2#issuecomment-290538039, or mute the thread https://github.com/notifications/unsubscribe-auth/APgjsChypsG2EeSO6KRqcRT2mqeNALPEks5rrBMagaJpZM4MpeTk .