Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lifecycle hooks #20

Closed
dy opened this issue Jun 5, 2019 · 2 comments
Closed

Lifecycle hooks #20

dy opened this issue Jun 5, 2019 · 2 comments
Labels
research Decision-making, arguments, discussion, comparison, design

Comments

@dy
Copy link
Owner

dy commented Jun 5, 2019

1.Should that be a counstructor instant run with registering fx ⭐

$(div, el => {
  // ~~constructor~~
  // render, since reruns any time any hook changes state
  let [state, set] = useState()

  // hooks
  mount(()=>{})
  update(()=>{})
  unmount(()=>{})

  // ~~detructor~~ never run
  return () => {}
})
  • a bit more flexibility in following classes paradigm (not sure how much is that a merit)
  • allows returning values
    easier to separate aspects, eg. put rendering in a separate aspect. Why though?
  • easier to condition advices via deps
    • no need to condition mount/unmount
  • closer to real AOP with pointcut-advice
    • in most cases that is run on mount/unmount anyways
  • technically can be merged with 2. and treat main fn as constructor and returned fn as destructor
    • not clear though when to call destructor lol. window.unload?
  • no way to define static props, the constructor is called per-element instance in DOM.
    • define them outside of aspect
  • an easier way to register all required listeners
    $(target, el => {
    let [a, b, c] = attr('a', 'b', 'c')
    update(fn, [a, b])
    })
    • ok, we read attributes, but the update - what deps should we pass to it to indicate what to observe? Should a,b,c be sort of proxy objects? Or again - primitive wrappers? Confusing!
      • Not necessary! Attributes can be just values, that we can parse later. Essentially it can just register listeners for attributes, that's it, so whenever attributes change, main method runs, that's it.
      • Maybe not necessarily that should be that bad. Other hooks can save situation, like state - so that the main method is run any time state is set.
  • clearer terminology from AOP
    ~ possibly less complacency with vanilla packages, alhough... constructor once seems what they're doing
    ~ doubtful situation if we init element anywhere else but mount.
  • inconsistency with selectors: for selectors this is run always on mount.
  • can be confusing to have aspect run for unmounted element, possibly better delegate unmounts to direct functions, since access to them is present
    . main method is not constructor. It is "render". An it is run whenever observable state changes.
    • that leads to 2.
      . constructor is used to init data placeholders, mostly it.
      ? how about aspect of offline canvas?

2. or fx hook straight ahead

$(div, el => {
  // mount or update
  return () => { /* destroy */ }
})
  • 1st-class shared state, no redundant scoping
  • no off-react conventions, more react-friendly
  • possibly easier to handle useEffect:
$(target, el => {
let x = attr('x')
useEffect(() => {}, [x])
})
  • although that observes all attribute changes
    • we anyways have to observe all attributes and subfilter some
    • we can register observers on mount - no sense to observe unmounted components
  • augmentor-compatible
  • that seems to be like hooks inside of element-effect hook.
  • no way to make sense of returned value or to have multiple returned values
    ? how to init stuff in unmounted component? Eg. custom element constructor?
    ? need we? What if we ignore off-mount components? $('selector') is anyways always affects real elements, can't init on unmounted elements.
  • weird aspect - that ignores element until it is mounted.
$(div, el => {
  // called only on mount - confusing!
})

The dispute seems to be returned unmount callback vs fulltime aspect.
The winner is 1. - that keeps promise for non-dom aspects, as well as enables unmounted elements. Also that makes lifecycle pointcuts more apparent.

@dy dy closed this as completed Jun 10, 2019
@dy
Copy link
Owner Author

dy commented Jun 12, 2019

! quite elegant mount-fx solution is mount(() => () => /* unmount */)

@dy
Copy link
Owner Author

dy commented Jun 12, 2019

? should selector aspects call destructor on unmount?

  • sounds meaningful to free memory
    − we [can] keep aspects as weak refs
    • still destructor is meaningful to clean up aspect
      . there's no destructor. There's main render and mount/unmount hooks.
      ? should non-selector aspects keep element reference regardless of mount/unmount?
      . possibly such "independent" elements should be handled in reference to context aspects, so if they disappear from the parent aspect's scope, their own aspect's destructor is called. But if they were initialized at the root, eg. $(document.body), then destructor is impossible to be reached.
      . for some real elements aspects can create blocking refs. For example, user wants to remove this element - but if there was an aspect registered at the root level as $(el, aspect), this aspect will remain after the mount/unmount. Best we can - keep aspects as weak as possible and encourage removing refs on unmount.
      . without mount/unmount hooks we'd re-register state every re-render, so they should be scoped.

@dy dy added the research Decision-making, arguments, discussion, comparison, design label Aug 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
research Decision-making, arguments, discussion, comparison, design
Projects
None yet
Development

No branches or pull requests

1 participant