bevacqua/react-dragula

Accessing Child Items in dragula callbacks

seanoshea opened this issue ยท 15 comments

Hi there,

I'm struggling to understand the best way to map the dom elements passed back in dragula callbacks to react child items. My code is as follows:

    componentDidMount: function () {
      var container = React.findDOMNode(this),
      drake = ReactDragula([container], {
        moves: function (el, source, handle, sibling) {
          // there are some items in the list of children associated with this container
          // which should not be draggable. Identifying these by their class name feels
          // somewhat wrong (shouldnt be reaching into the DOM to understand a child's state?).
          return el.className !== 'draggable';
        },
        direction: 'horizontal'
      });
      drake.on('drop', (el, target, source, sibling) => {
        // how to I convert the DOM `el` here into the corresponding child item
        this.props.moveFrameCallback(item.id);
      });
    }

The el parameter passed into the drop method is a dom child element of the dnd container. Was wondering what's the best way to map this dom element to the react child item so I can invoke a callback?

I'd like to be able to make an API call based on the drop action and need the id of the child element. The id of the child item is somewhat parsable in the data-reactid attribute of the dom node - is that where I should be taking it from, or is there a more advisable way?

Thanks again for dragula,

Sean

It appears that dragula tracks DOM elements instead of React components, but that doesn't make sense in a React app as you never really care about the DOM. :(

Yep - after reading some react documentation and reading this SO post , it appears that a mapping between dom nodes and react components isn't exact the react way of doing things.

In order for this to work, some the corresponding react component would need to be sent back in line 266 of dragula.js:

 else {
      drake.emit('drop', item, target, _source, _currentSibling);
    }

Based on this article, I think there'd (very understandably) be some resistance to leaking any react specific code into dragula.js to provide this react component in the callback.

@evandavis @bevacqua - Would there be any any way for react-dragula to accommodate this additional context?

Can't we just map the drake instance to the react component?

@bevacqua how do you propose doing that?

I haven't used React that much, but we could change react-dragula to fit React -- as long as dragula itself doesn't need to change to accomodate React we're fine. So, maybe we could do

In react-dragula:

drake.on('react-component', component => _component = component);

In user code:

drake.emit('react-component', component);

Where did we land with this? I am running into this problem now.

+1

I'm currently getting around this by assigning data-* attributes to the DOM elements, but would much prefer if there was another way :)

In the next version of React the data-reactid's will be removed, so you shouldn't try to map them to React components.

avk commented

Am I missing something? What's the point of react-dragula if it breaks how React works with the DOM?

I'm also unclear on how this project actually lets you use dragging and dropping to accomplish anything. Dragula is a very nice and lightweight project, it would be great to use this, but I'll check out http://gaearon.github.io/react-dnd/ for now.

Hey @bevacqua , is there any solution to this issue? It seems like we need some sort of callback like "onDrop" that includes info about the element being dragged.

... Does anyone have a solution or workaround to this issue?

avk commented

Given that my question was never addressed and this still seems to be antithetical to how React works by changing the DOM directly, I've abandoned this for http://gaearon.github.io/react-dnd/ as well.

I'm not seeing why using data attributes is so bad? I'm not seeing anything break. Take this example:

var listsNode = ReactDOM.findDOMNode(this.refs.lists);

drake.on('drop', function (el, target, source, sibling) {
    var listsNum = source.children.length;
    var i, j;

    for (i = 0; i < listsNum; i++) {
        console.log(source.children[i].dataset.oid);
    }

    for (j = 0; j < listsNum; j++) {
        console.log(listsNode.children[j].dataset.oid);
    }
});

In both instances the correct oid is logged. Data attributes aren't somehow "not React", they are valid HTML5 attributes and work fine with React (https://facebook.github.io/react/docs/jsx-gotchas.html#custom-html-attributes).

So what's wrong with using this method to update the order? @levrik We are not talking about the react- attributes, we are talking about custom html5 data attributes.

Seems like an easy and valid way to fix the problem to me.

Why is it not ok to read the DOM? Seems to me that accessing elements through data-something attributes does the same thing.