0

I have issue keeping ref of nested original element while cloned parent gets unmounted. Not sure what I am doing wrong.

Have page with structure like this

<Sortable>
   <Collapsible ref='Collapsible-1'>...</Collapsible>
   <Collapsible ref='Collapsible-2'>...</Collapsible>
</Sortable>
  1. Sortable component wraps each children to Sortable__item component
  2. When user starts sorting(dragging) one of Sortable__item components I React.cloneElement() original Sortable__item to display it as dragable shadow
  3. It gets cloned with all children, in this scenario with Collapsible component on which Page has ref['Collapsible-1'] saved. That ref on page gets changed to this shadows ref.
  4. Once touchEnd kicks in I update state of Sortable to not show shadow(it gets unmounted).
  5. When it gets unmounted it also removes ref inside Page(changes to null)
  6. ISSUE: page doesn't have ref to original Collapsible as first its got changed to shadow, and then shadow got unmounted so now its null

Quick hack/fix to solve this annoying issue. This way refs never get updated if they already exist. This is pretty bad, but I don't know how else prevent this. Anyone can point me to right direction?

let registerRef = function(name, item){
    if(this.items[name]) return;
    this.items[name] = item;
}
<Sortable>
    <Collapsible ref={registerRef.bind(this,'Collapsible-1')}>...</Collapsible>
    <Collapsible ref={registerRef.bind(this,'Collapsible-2')}>...</Collapsible>
</Sortable>
Oozhaa
  • 181
  • 1
  • 12
  • Could you pass {ref: null} as part of the props you pass to cloneElement? That way the clone won't include your ref function. – TomW Mar 06 '16 at 00:34
  • Yes, I am already passing new ref when cloning, but I am cloning Sortable__item which inside has children which has been refrenced in top level parent. ref gets overwritten to cloned element, but its children still are linking back to Page. – Oozhaa Mar 06 '16 at 01:00
  • I think to replace child refs you'll need to call React.Children.map and cloneElement the children too. – TomW Mar 06 '16 at 10:48
  • Thanks TomW for helping me out! – Oozhaa Mar 06 '16 at 18:11

1 Answers1

0

I have re-thought my solution, and changed how it works.

Idea to duplicate entire child with all components inside, only to show it as draggable shadow, is bad idea! It is performance heavy task to do and also it causes unexpected results for reactjs refs.

I have chosen other solution. When I start sorting(dragging) child I allow user to take it out from list and move it(I mean I apply display: absolute; and some css transforms to follow finger). Then I create div inside list like a dropbox to indicate where draggable item will be droped on onTouchEnd. This way is much better for performance because I am not duplicating entire item DOM tree and it doesn't cause issue with duplication of children refs.

Solved.

Oozhaa
  • 181
  • 1
  • 12