6

I've been struggling to implement this example noted in the react-sortable-hoc examples page, specifically with the autoscroll behavior within a table. Unfortunately it doesn't look as though source code lives in the examples directory of the repository.

Although the code I've implemented in the codesandbox below is a very simple example, I've been pouring over this for hours, using useWindowAsScrollContainer and getContainer with refs, but nothing seems to resolve the issue.

That said, here's the behavior I'm noting: when scrolling out of the container, and even out of the window, the autoscroll feature never engages. I even resorted to returning document.body with getContainer which should limit the container, but can't seem to replicate the behavior as noted in the repository's example.

Also, although I've specified a fixed height and width on the SortableTable component, ideally this should be wrapped with <AutoSizer />, but removed that for the time being to eliminate any side effects.

https://codesandbox.io/s/mysortabletable-zi94g?file=/MySortableTable.js

  • react-sortable-hoc: 1.11.0
  • react-virtualized: 9.7.5

enter image description here

Nimantha
  • 6,405
  • 6
  • 28
  • 69
lux
  • 8,315
  • 7
  • 36
  • 49

1 Answers1

4

You need to provider the container to the Sortable component to which it must restrict the sortableElement when using 3rd party libraries for rendering using the getContainer prop.

As per the react-sortable-hoc documentation:

getContainer is an Optional function to return the scrollable container element. This property defaults to the SortableContainer element itself or (if useWindowAsScrollContainer is true) the window. Use this function to specify a custom container object (eg this is useful for integrating with certain 3rd party components such as FlexTable). This function is passed a single parameter (the wrappedInstance React element) and it is expected to return a DOM element.

Now since you cannot pass a direct ref to the child, you can write a small wrapper over the Table component before passing it to the HOC

const MyTable = ({ tableRef, ...rest }) => {
    return <Table ref={this.props.tableRef} {...rest} />;
}
const SortableTable = SortableContainer(MyTable);
const SortableTableRowRenderer = SortableElement(defaultTableRowRenderer);

/**
 * Define the table schema
 */
const schema = [
  { dataKey: "col1", label: "Column 1" },
  { dataKey: "col2", label: "Column 2" }
];

/**
 * Generate row data according to the schema above
 * @param {*} rowCount
 */
function generateRows(rowCount) {
  const rows = [];
  for (let i = 0; i < rowCount; i++) {
    rows.push({ col1: i, col2: i * i });
  }
  return rows;
}

class MySortableTable extends Component {
  state = {
    schema,
    rows: generateRows(200)
  };

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

  rowRenderer = props => {
    return <SortableTableRowRenderer {...props} />;
  };

  getRow = ({ index }) => {
    const { rows } = this.state;
    return rows[index];
  };

  render() {
    const { rows, schema } = this.state;

    return (
      <SortableTable
        width={500}
        height={500}
        headerHeight={32}
        rowHeight={32}
        tableRef={ref => (this.tableRef = ref)}
        getContainer={() => ReactDOM.findDOMNode(this.tableRef.Grid)}
        rowCount={rows.length}
        rowGetter={this.getRow}
        onSortEnd={this.onSortEnd}
        rowRenderer={this.rowRenderer}
      >
        {schema.map(col => (
          <Column {...col} key={col.dataKey} width={100} />
        ))}
      </SortableTable>
    );
  }
}

Working demo

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • This is brilliant - thank you very much, I knew I was missing something with a ref to the table, and this is it. I'm going to attempt to wrap this with and hopefully I don't hit any subsequent issues. Thanks again! – lux May 24 '20 at 18:53
  • 1
    Glad to have helped :-) – Shubham Khatri May 24 '20 at 18:57
  • 1
    Thanks! Even though it's a bit outdate as we are now mostly using functional components. The important bit here is `getContainer={() => ReactDOM.findDOMNode(this.tableRef.Grid)}` – Andrej Jurkin Aug 23 '21 at 10:44