5

I want to use react-sortable-hoc with react-virtualized's MultiGrid. More specifically I would like to be able to sort the rows in the lower right grid.

1st attempt

I'm creating a SortableMultiGrid using

const SortableMultiGrid = SortableContainer(MultiGrid, {
  withRef: true,
});

But when this mounts I get an error, with this message

Cannot read property 'ownerDocument' of undefined

The error originates from the SortableContainer's componentDidMount method.

2nd attempt

I found that the SortableContainer has a getContainer property, which is called just above the code that throws the error:

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.

It's called with the MultiGrid component instance but when I try to get the DOM node from that, it returns null:

getContainer={e => {
  const multiGrid = ReactDOM.findDOMNode(e);
  // multiGrid is null - I must return an HTMLElement
}}

I suspect that what this might be caused by the MultiGrid component not yet being mounted and I suspect that what I'm seeing is related to https://github.com/clauderic/react-sortable-hoc/issues/135.

3rd attempt - works, but it's a hack

I figured that I could probably trick the SortableContainer by first returning something that wouldn't throw the error and then when the reference to the lower right grid inside the multigrid can be determined, I could call the componentDidMount of the SortableContainer again.

<SortableMultiGrid
  // ...
  ref={sortableGrid => {
    if (sortableGrid) {
      const multiGrid = sortableGrid.getWrappedInstance();
      if (multiGrid && multiGrid._bottomRightGrid) {
        const bottomRightGrid = multiGrid._bottomRightGrid;
        const bottomRightGridNode = ReactDOM.findDOMNode(
          bottomRightGrid
        );
        this.bottomRightGrid = bottomRightGridNode;
        // HACK: We shouldn't ever call componentDidMount on components
        sortableGrid.componentDidMount();
      }
    }
  }}
  getContainer={e => {
    if (this.bottomRightGrid) {
      return this.bottomRightGrid;
    } else {
      // If its unknown - return something that wont throw errors
      return {
        ownerDocument: document,
        addEventListener: () => { },
        removeEventListener: () => { }
      };
    }
  }}
/>

This actually seem to work! But I would still like to know if anyone has ideas on how this could be achieved with more elegance or how either of the two libs should change to fix this issue.


CodeSandbox

I've made two sandboxes to illustrate this:

  1. The first is a functional sortable Grid (I havn't implemented for the end state to be persisted): https://codesandbox.io/s/710kxo247x. I implemented a "rowRangeRenderer" that renders rows of cells (note its not fully optimized with caching when scrolling), to replace the defaultCellRangeRenderer and allow for the rows to be wrapped by the SortableElement HOC.
  2. Is an attempt to use a MultiGrid instead of a Grid - which shows the error mentioned above: https://codesandbox.io/s/1z390ow44
  3. The third attempt - it sort of works, but it's a hack https://codesandbox.io/s/pprwo6m350
kraenhansen
  • 1,535
  • 2
  • 15
  • 26
  • I would be pleasantly surprised if `MultiGrid` worked with Clauderic's sortable HOC. I've never tried it. – bvaughn Nov 18 '17 at 17:09
  • @brianvaughn To me it seems like a timing issue. The `getContainer` is called from the `SortableContainer`'s componentDidMount - but for some reason the wrapped component (the MultiGrid) has not been mounted and findDOMNode returns null. I don't think I know enough about React and the order of components getting mounted understand which of the two libraries are making a bold assumption here. – kraenhansen Nov 18 '17 at 18:45
  • Children should be mounted by the time a component's `componentDidMount` method is called, unless there's some conditional rendering. In the case of `MultiGrid`, it renders `null` if there are no rows/cols yet (https://github.com/bvaughn/react-virtualized/blob/master/source/MultiGrid/MultiGrid.js#L266-L271) Could this be the cause of what you're seeing? – bvaughn Nov 19 '17 at 16:32

1 Answers1

0

Although it had been 3 years, but I recently have same requirement and found this is really helpful, I use ReactDOM.findDOMNode(this) as container and it works. https://codesandbox.io/s/sortable-multigrid-hacked-forked-3mj8e?file=/MySortableMultiGrid.js