draggable: Unable to use this with ReactJS

I’ve the following html structure:

<div className="items__food">
  <div className="food food--apple">
    <img src={Apple} alt="Apple" />
  </div>
  <div className="food food--banana">
    <img src={Banana} alt="Banana" />
  </div>
  <div className="food food--bread">
    <img src={Bread} alt="Bread" />
  </div>
</div>

And in my componentDidMount, I’m doing:

new Draggable(document.querySelectorAll('.items__food'))
  .on('drag:start', () => console.log('drag:start'))
  .on('drag:move',  () => console.log('drag:move'))
  .on('drag:stop',  () => console.log('drag:stop'));

However, I’m unable to drag any .food items and as a result, nothing is outputted on the console.

screen shot 2017-10-01 at 8 40 01 am As you can see that `.items__food` isn't empty inside the `componentDidMount` lifecycle hook. Am I missing something here?

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Comments: 28 (3 by maintainers)

Most upvoted comments

There are plans on releasing a react component as a separate bundle for this repo.

React support would be awesome.

I just threw together a very simple example integrating the Sortable portion of this library with React if anyone wants to check it out for reference.

Repo Demo

@ghoshnirmalya should definitely work with React. You would also need to override the componentDidUpdate to figure out if, e.g. children elements have changed, or you could see if a sortable:sorted has fired (implementation is up to you). Or you could also just return false within componentDidUpdate which tells react to never re-render.

There are plans on releasing a react component as a separate bundle for this repo.

Since draggable does it on the fly while dragging, there’s no way to cancel it

@STenorio99 this is true, Sortable, Swappable and Droppable do DOM manipulations as you drag around, as supposed to on drag end. This makes this draggable library different than others, but we could add a traditional sortable module (built on top of Draggable) that performs DOM manipulation on drag end instead.

You can cancel most DOM manipulations via canceling events, e.g.

new Swappable(containers)
  .on('swappable:swapped', (event) => event.cancel())

We are missing the cancelable action for sortable:sorted, but we can easily add it, which is the plan. It would work like swappable https://github.com/shopify/draggable#events-3

I hope that answered a lot of the questions in this issue?

@tsov @beefchimi

Done and published! 😃

Repo: https://github.com/wuweiweiwu/react-shopify-draggable Simple Demo: https://weiweiwu.me/react-shopify-draggable/ NPM: https://www.npmjs.com/package/@wuweiweiwu/react-shopify-draggable

Implementation details: https://github.com/wuweiweiwu/react-shopify-draggable#implementation-details on how I was able to pass options down via context. And update props like id className and style without rerendering

@jmakGH I took your example + some styling to create my simple example. And it is pasted below.

render() {
  return (
    <div className="App">
      <div className="App-body">
        <div className="App-body-count">
          <h1 className="App-body-count-text">Block count:</h1>
          <input
            type="number"
            className="App-body-count-input"
            value={this.state.blockCount}
            onChange={this.handleBlockCount}
          />
        </div>
        <DraggableContainer
          as="div"
          type="sortable"
          className="BlockGenerator"
        >
          {Array.from(Array(this.state.blockCount).keys()).map(number => (
            <DraggableItem
              as="div"
              className="Block"
              style={{ backgroundColor: randomColor() }}
            >
              {number}
            </DraggableItem>
          ))}
        </DraggableContainer>
      </div>
    </div>
  );
}

Also working on some more advanced examples in Storybook

I would love any feedback. Enjoy 💯

We do not. that was supposed to be a motivational comment to add react support/docs soon

No problem guys, although I should note it’s definitely a rough draft. The current setup works outside of the React lifecycle, meaning that sorting the blocks only changes the UI representation but not the actual state.

Project is updated and now runs all updates properly through React.

All the hooks are there though to update state accordingly and I’ll be getting this more Reactified in the upcoming days as well as getting a few more different examples up.

While we’re at it, what about other frameworks such as VueJS?

@tsov @beefchimi I’m going to start working on a React wrapper for this! 😃 I’ll keep you guys posted

I just encountered the issue with react not being aware of the DOM manipulation draggable does. Since draggable does it on the fly while dragging, there’s no way to cancel it (from what I can see) like you can with the alike jQuery UI Sortable and let React do it instead.

If for some reason you don’t want to use the awesome react-shopify-draggable, I’ve written a short tutorial (https://afi.io/blog/how-to-use-shopify-draggable-with-react/) that shows how you can make shopify draggable work with react.

Update # 2:

95% DONE!!! 😃

repo: https://github.com/wuweiweiwu/react-shopify-draggable

I just need to finish some enzyme tests and flesh out the demos and update the README

Will update soon.

ps: react-shopify-draggable is actually taken on npm already but it just has some boilerplate code that that just create a Draggable instance and nothing else. So I will be publishing it as a scoped module

yarn add @wuweiweiwu/react-shopify-draggable

Update # 1:

Design for Draggable

Supports single containers

DraggableContainer
	props:
		draggable: string
		handle: string
		as: string // what to render the container as
		className: string // classname for the container
		style: {[string]:string} //inline styling	
		delay: number
		classes: {[string]: string} // add classes to elements to indicate state
		draggableRef: (Draggable) => void // ref so you can access the Draggable object to override stuff if u want. Like event listeners
                 // and all the React synthetic event handlers :) 
		
Draggable
	context: 
		draggable: string // classnames for the query selector. Added onto classname
	
	props:
		as: string
		className: string // classname for the component
		style: {[string]:string} //inline style
		children: Nodes // what to render inside (even react components)
                 // and all the React synthetic event handlers :) 
	
Handle
	context:
		handle: // classnames for the handle. Added onto classname

	props:
		as: string
		className: string // classname for the component
		style: {[string]: string}
                 // and all the React synthetic event handlers :) 

Usage would be like:

<DraggableContainer draggable="whatever" handle="whatever2">
    <Draggable children={<Handle/>} />
</DraggableContainer>

Using the provider pattern to pass the classnames to the respective children without explicitly passing the props in Draggable and Handle. I should have it implemented soon 😃

I don’t think you can do this (well, you can, but you shouldn’t), b/c react is not aware of what draggable does to your DOM nodes so react is unable to compute valid DOM representation for the next render.

Interested to see how to integrate with React - I had some strange behaviour with elements duplicating. 😃

@jmakGH thank you so much! I couldn’t figure it out by myself