inesita-rb / inesita

Frontend web application framework in Ruby using Opal.
https://inesita.fazibear.me/
MIT License
259 stars 15 forks source link

Bring back 'Component#after_render' #32

Closed jmstacey closed 7 years ago

jmstacey commented 7 years ago

This component method callback is useful for JQuery plugins that change the real DOM and need the virtual DOM render to be patched before activating.

Example:

def before_render
  Element['#outline'].nestable('destroy')
end

def after_render
  Element['#outline'].nestable({ ... options ...}.to_n)
end

def render
  div id: "outline"
end
fazibear commented 7 years ago

after_render callback is a bad idea. They have big performance overhead. You should use virtual-dom hooks instead.

jmstacey commented 7 years ago

Renamed to on_mounted. This let's us do something like the following where on_mounted callbacks are made after the component is rendered, and will_unmount when the component is being removed from the virtual DOM but before it's removed from DOM.

This would be the ideal use case, but facilitates use of legacy code that directly manipulates the DOM.

def will_unmount
  Element['#outline'].nestable('destroy')
end

def on_mounted
  Element['#outline'].nestable({ 'json': store.app.state.visible_data, 'callback': method(:on_dd_change).to_proc }.to_n)
end

def render
  div class: "dd", id: "outline", hook: unhook(:will_unmount)
  . . .
end
jmstacey commented 7 years ago

Reopening. Renamed the source branch and GH auto closed.

fazibear commented 7 years ago

Just like I said 'after_render' callback is a very bad idea. There is performance overhead even if you don't use it. Use virtual-dom hooks instead.

Hook gives you a reference to given node, just after mount.

Here is the example:

  def after_render(node)
    Element[node.to_n].nestable({ 'json': store.app.state.visible_data, 'callback': -> { on_dd_change(l, e) } }.to_n) # #to_n converts to native javascript. Provided by opal-jquery
    # Todo (caution): nestable binding is on real DOM and is likely to break on route changes. Consider a "terminate" equivalent to unload on other pages.
  end

  def render
    div class: "dd", id: "outline", hook: hook(:after_render)
    ..
  end