hyper-react
hyper-react copied to clipboard
refs callbacks
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}" }
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" }
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
@zetachang what version were you trying this on? Perhaps this was in master?
@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...
It works guys... thank you a lot
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)
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
@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| ... }
@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?
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 https://github.com/facebook/react/issues/3234