hyper-react icon indicating copy to clipboard operation
hyper-react copied to clipboard

Element is not removed from corresponding buffer when passed as prop unless element is in current buffer

Open zetachang opened this issue 7 years ago • 10 comments

A bug occurred while investigating #122,

class MyComponent
  include React::Component
  param :tip

  def render
    div {
      params.tip
    }
  end
end

class TooltipExample
  include React::Component

  def render
    tip = span { "this is a tip" } # <---- key is that the element is generated outside
    div(id: "outer") {
      MyComponent(tip: tip) # < ---- where its used 
    }
  end
end

will raise

Exception raised while rendering #TooltipExample:0x209c: a component's render method must generate and return exactly 1 element or a string. Instead 2 elements were generated.

The span { "this is a tip" } is not removed from the correct buffer.

zetachang avatar Nov 26 '16 06:11 zetachang

try

params.tip.render

This may fix it..

catmando avatar Dec 01 '16 18:12 catmando

Yeah, that will fix it, but I think this could be done automatically. Remove it from current @buffer won't work because span { "this is a tip" } is in the outer buffer.

zetachang avatar Dec 04 '16 05:12 zetachang

it is removed from the outer buffer automatically when it is passed as a param.

We have to do it this way to allow for native components to easily accept Element params.

At least that was my theory :-)

catmando avatar Dec 04 '16 13:12 catmando

I think my latest attemp show that even manualy “params.tip.render” won't work.

But anyway, I will verify it again and provide a detailed report and continue the discussion on how we can fix this.

Mitch VanDuyn [email protected] 於 2016年12月4日週日 下午9:24 寫道:

it is removed from the outer buffer automatically when it is passed as a param.

We have to do it this way to allow for native components to easily accept Element params.

At least that was my theory :-)

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ruby-hyperloop/hyper-react/issues/189#issuecomment-264703779, or mute the thread https://github.com/notifications/unsubscribe-auth/AAzRJVlbRJoWxyu47acSHFspLBFw5-WVks5rEr8HgaJpZM4K806c .

zetachang avatar Dec 04 '16 13:12 zetachang

I've verified again, params.tip.render won't work. But tip = span { "this is a tip" }.delete will work.

I think the reason is that by wrapping another tag will create a new buffer, thus the automatically removal won't work.

# automatically removal won't work
div(id: "outer") {
   MyComponent(tip: tip)
 }

# will work
MyComponent(tip: tip)

So I think we might need to keep a reference to the parent buffer, and traversal all the way up to the top buffer to remove the element.

zetachang avatar Dec 06 '16 15:12 zetachang

Sure that makes sense, but there is code to automatically remove the element when it's first passed as a parameter. That should be working in this case...

catmando avatar Dec 06 '16 15:12 catmando

Also sorry, originally I said adding .render would fix it. That's only partially true. .render is needed to render the element, but the bug is that it should already be removed, from the parents buffer

catmando avatar Dec 06 '16 15:12 catmando

All this applies I guess only to Opal components, which go through rendering context. I think the point of the original issue is we should apply .as_node and .to_n to all elements before shipping them to a native component

catmando avatar Dec 06 '16 16:12 catmando

Yeah, this one should be considered a separate issue.

zetachang avatar Dec 06 '16 16:12 zetachang

OKAY! I got it now (you probably knew this, but I was missing the point...)

In this case we have the element tip being generated one layer outside where it is used, so yes we will have to search up tree of buffers (which will require a small mod as currently the buffer stack is stored as local vars, but not tough to fix.)

I updated the name of the problem too.

catmando avatar Dec 06 '16 17:12 catmando