Skip to content
This repository has been archived by the owner on Oct 19, 2018. It is now read-only.

refs callbacks #168

Open
leizzer opened this issue Oct 4, 2016 · 10 comments
Open

refs callbacks #168

leizzer opened this issue Oct 4, 2016 · 10 comments

Comments

@leizzer
Copy link

leizzer commented Oct 4, 2016

I'm willing add a callback to a ref as they said in React documentation
https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute

They said that the string refs could be deprecated.

What I was trying to achieve was something like this:

class Parent < React::Component::Base
  def change_child_state
    self.refs._child.state.lucky! true
  end

  def render
    Other(ref: ->{|c| self._child = child})
    button(value: 'Go').on :click do
      change_child_state
    end
  end
end

What @catmando kindly proposed me is:

module RefCallBacks
 param :on_ref, default: nil, allow_nil: true, type: Proc
 after_mount do
   params.ref(self)
 end
end

  class IllCallYou < React::Component::Base
    include RefCallBack
    ... go on with life
  end

  ... somewhere else
  IllCallYou(...).on(:ref) { |comp|  puts "comp = #{comp}" }
@zetachang
Copy link
Member

I've tried by passing a Proc as ref, and it works as the original ref callback. So you could actually write like this

class Hello < React::Component::Base
  attr_accessor :my_span

  def modify_my_span
    if my_span
      `#{my_span}.innerHTML = 'bla'`
    end
  end

  def render
    div{
      button{ 'click me' }.on(:click) { modify_my_span }
      span(ref: ->(dom_node){ self.my_span = dom_node }) { "Hello World" }
    }
  end
end

Or even shorter by passing the setter method as ref,

span(ref: method(:my_span=).to_proc) { "Hello World" }

@leizzer
Copy link
Author

leizzer commented Oct 5, 2016

This didn't work, it doesn't even puts 'hi' unless I remove the span in the render.

could it be because I am using reactrb-express?

def clicked
  puts 'hi'
  if my_span
    `#{my_span}.innerHTML = 'bla'`
  end
end

def render
  span(ref: ->(dom_node){ self.my_span = dom_node }) { "Hello World" }
  button do
    'Go'
  end.on :click do
    clicked
  end
end

@catmando
Copy link
Contributor

catmando commented Oct 5, 2016

@zetachang what version were you trying this on? Perhaps this was in master?

@catmando
Copy link
Contributor

catmando commented Oct 5, 2016

@leizzer are you doing this with reactrb-express? If so try again... I just realized that reactrb-express was about 5 versions behind reactrb. fixed now...

@leizzer
Copy link
Author

leizzer commented Oct 5, 2016

It works guys... thank you a lot

@catmando catmando closed this as completed Oct 6, 2016
@catmando catmando reopened this Oct 6, 2016
@catmando
Copy link
Contributor

catmando commented Oct 6, 2016

okay but I think this is still an issue. As ref is a kind of call back to be consistent we should add a callback method (like on, but for ref)

For example: .on(:mount) { |ref| ... } (nice and simple)

@leizzer
Copy link
Author

leizzer commented Oct 6, 2016

I don't know.... doing it from ref respects React docs... But it would be nice if I don't need to embed js to use the dom_node.

Also reading the React docs says that if the element is an input, it returns the component instance but if it is other kind it returns the dom element... I didn't try it with inputs in reactrb

@zetachang
Copy link
Member

@catmando , yeah, providing a callback would be consistent, but the ref callback is also called when unmount happen, so may be .on(:ref) { |dom_node_or_instance| ... }

@catmando
Copy link
Contributor

catmando commented Oct 7, 2016

@leizzer - its just a syntactic difference. Unlike JS, ruby has several different ways to provide callbacks. In keeping with ruby philosophy it is good provide several (consistent) ways to get the job done, and let the programmer decide. BTW not sure what you mean't by "embed js" above examples do no have any js in them???

@zetachang - good catch on unmount. The on method now allows multiple names... so you can do .on(:mount, :unmount) if you want both, but I would guess in many cases the mount callback would want to be different than the unmount. So this way the programmer can decide, and i think it reads much better than :ref. what does that mean anyway?

@zetachang
Copy link
Member

The ref callback is used to save the actual instance or dom node for further manipulate, the callback will be called after mounted, and called again with null when element is unmounted. So the usual use case is just as the above code sample: set & unset a property in a same callback given that you usually don't want to keep the DOM node if it's already unmounted.

Many people found the ref callback approach not intuitive, but this is actually a not bad solution so far given that string ref approach introduce ambiguity when the parent-child relationship is broken. For the discussion of the API change, see the original reactjs issue facebook/react#3234

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants