5
votes

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
1
I would be pleasantly surprised if MultiGrid worked with Clauderic's sortable HOC. I've never tried it. - bvaughn
@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
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 (github.com/bvaughn/react-virtualized/blob/master/source/…) Could this be the cause of what you're seeing? - bvaughn

1 Answers

0
votes

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