Search code examples
reactjsdrag-and-dropdraggable

converting class component to functional error


I am using the react-sortable-hoc package and want to use it in a functional component instead. I have tried to convert it but there is a line that is giving me an error.

The list shows up and I can drag any element but as soon as I drop it I get the error

Cannot read property 'slice' of undefined

It looks as if it is posting to this line:

items: arrayMove(items, oldIndex, newIndex),

Here is the class based version:

import React, {Component} from 'react';
import {render} from 'react-dom';
import {sortableContainer, sortableElement} from 'react-sortable-hoc';
import arrayMove from 'array-move';

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

const SortableContainer = sortableContainer(({children}) => {
  return <ul>{children}</ul>;
});

class App extends Component {
  state = {
    items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6'],
  };

  onSortEnd = ({oldIndex, newIndex}) => {
    this.setState(({items}) => ({
      items: arrayMove(items, oldIndex, newIndex),
    }));
  };

  render() {
    const {items} = this.state;

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

render(<App />, document.getElementById('root'));

And the version I am trying to put together:

import React, { useState } from "react";
import { sortableContainer, sortableElement } from "react-sortable-hoc";
import arrayMove from "array-move";

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

const SortableContainer = sortableContainer(({ children }) => {
  return <ul>{children}</ul>;
});

const Dashboard = () => {
  const [items, setItems] = useState([
    "Item 1",
    "Item 2",
    "Item 3",
    "Item 4",
    "Item 5",
    "Item 6",
  ]);

  const onSortEnd = ({ oldIndex, newIndex }) => {
    setItems(({ items }) => ({
      items: arrayMove(items, oldIndex, newIndex),
    }));
  };

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

export default Dashboard;

Solution

  • You need not destructure items from setItems callback as state doesn't store the object in your case but an array. Also you must not set the value back as an object, instead it should be an array again

    setItems((items) => arrayMove(items, oldIndex, newIndex));