javascriptreactjsdrag-and-dropreact-sortable-hoc

Can anyone advise on the best way to integrate React Drag/Drop Lists with dynamic values from Redux?


I need the sortable drag/drop component to be able to re-render with new values upon a user's button click from another container and still retain drag/drop functionality. If the list contains [a, b, c] at first I need it to still work when they user clicks a button that would re-render the list as [d, e, f, g], for example.

I'm running into the same issue with react-sortable-hoc, react-beautiful-dnd and some others. All of these libraries use an array to populate their drag and drop list component, typically named this.state.items in the basic examples. They make use of a function called onSortEnd to handle the rearrangement of items. The basic code example for react-sortable-hoc and which includes my update this.state.items in render() are below:

import React, {Component} from 'react';
import {render} from 'react-dom';
import {SortableContainer, SortableElement, arrayMove} from 'react-sortable-hoc';

const SortableItem = SortableElement(({value}) =>
  <li>{value}</li>
);

const SortableList = SortableContainer(({items}) => {
  return (
    <ul>
      {items.map((value, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} />
      ))}
    </ul>
  );
});

class SelectedItem extends Component {
  state = {
    items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6'],
  };
  onSortEnd = ({oldIndex, newIndex}) => {
    this.setState({
      items: arrayMove(this.state.items, oldIndex, newIndex),
    });
  };
  render() {

// MY CODE ADDITIONS!! THIS IS WHERE THE LIST ITEM GETS UPDATED.

    this.state.items = [this.props.selectedItem.node.title,
                this.props.selectedItem.node.subtitle,
                this.props.selectedItem.treeIndex]; 

     return <SortableList items={this.state.items} onSortEnd={this.onSortEnd} />;
  }
}

function mapStateToProps(state)
{
    return {
        selectedItem: state.activeItem
    };
}

export default connect(mapStateToProps)(SelectedItem);

Everything works fine with drag/drop at first. However if I change the value of items[] in render(), the new list properly renders. However the drag/drop fails. It looks like it will work when dragging; the selected element moves and the target location looks like it will accept it but onMouseRelease everything snaps back to the original.

I've put console.log commands after the array move to confirm that the list in items gets reordered as desired. It just doesn't happen visually. There's no console error when dragging/dropping.

Any help would be appreciated.


Solution

  • I resolved this by leveraging the getDerivedStateFromProps lifecycle method to update the items state.