fkhadra / react-contexify

👌 Add a context menu to your react app with ease
https://fkhadra.github.io/react-contexify/
MIT License
1.17k stars 118 forks source link

this.menu is null when setting position #43

Closed jktravis closed 6 years ago

jktravis commented 6 years ago

Hi. I'm hoping you can help with this error. Somehow, it seems like the menu isn't be set in certain situations. I'm adding a context menu in a react-virtualized grid that needs drag and drop. The app has multiple routes provided by react-router. All this to say that I'm having trouble getting the error to occur in isolation.

The problem seems to be when I navigate to the page with this particular menu (other menus seem to be okay). The first right-click causes an error:

    Uncaught TypeError: Cannot read property 'offsetWidth' of null
            at ContextMenu.setMenuPosition (ContextMenu.js:154)
            at commitCallbacks (react-dom.development.js:6163)
            at commitLifeCycles (react-dom.development.js:8784)
            at commitAllLifeCycles (react-dom.development.js:9946)
            at HTMLUnknownElement.callCallback (react-dom.development.js:542)
            at Object.invokeGuardedCallbackDev (react-dom.development.js:581)
            at invokeGuardedCallback (react-dom.development.js:438)
            at commitRoot (react-dom.development.js:10050)
            at performWorkOnRoot (react-dom.development.js:11017)
            at performWork (react-dom.development.js:10967)

Clicking through the error, the browser complains about this section of code:

    //....
    key: 'setMenuPosition',
    value: function setMenuPosition() {
      var browserSize = {
        width: window.innerWidth,
        height: window.innerHeight
      };

      var menuSize = {
        width: this.menu.offsetWidth, // <--- errors here
        height: this.menu.offsetHeight
      };

      var _state = this.state,
          x = _state.x,
          y = _state.y;
    //....

Stepping through the code, the menu does show up for an instant before it goes away.

What's also interesting is that if I load the page directly (that is, don't navigate to it through menus), right-click works fine.

Here's the component I'm wrapping.

class Front extends Component {
  componentDidMount() {
    const dragPreview = createDragPreviewImage();
    dragPreview.onload = () => this.props.connectDragPreview(dragPreview);
  }

  render() {
    const { appropriation, style, connectDragSource } = this.props;
    const text = appropriation.get('Name');

    return (
      <ContextMenuProvider id="phase_menu"
                           ref={ref => {
                             const node = findDOMNode(ref);
                             connectDragSource(node);
                           }}
      >
        <div style={style}>
          {text}
          <FaFileTextO/>
        </div>
      </ContextMenuProvider>
    );
  }
}

Here's the context menu component

class PhaseContextMenu extends Component {
  render() {
    return (
      <ContextMenu id="phase_menu">
        <Item onClick={() => console.log("Open")}> Open </Item>
        <Item onClick={() => console.log("Close")}> Close </Item>
        <Item onClick={() => console.log("Neither")}> Neither </Item>
      </ContextMenu>
    );
  }
}

And here's the use of the menu.

class VirtualGrid extends PureComponent {
//...
  render() {
    return (
      <Fragment>
        <ScrollSync>
          {/* All the grid stuff including phases, which are context-menu wrapped.*/}
        </ScrollSync>
        <PhaseContextMenu/>
      </Fragment>
    );
  }
}
fkhadra commented 6 years ago

Hello @jktravis,

The others working ContextMenu uses the same setup? (react-dnd, different route)

jktravis commented 6 years ago

Pretty close. There are a few that are not on a virtualized grid. Other than that, yeah. This one takes three grids and kind of stitches them together to give a header top, header left, and then the main grid.

I noticed though, that if I do the drag/drop action before right-clicking, it doesn’t seem to do it.

jktravis commented 6 years ago

Found the problem! Apparently, the component I was loading the menu in is loading multiple times on the page, causing effectively, duplicate menus all with the same name.

Sorry to bother you with this.

fkhadra commented 6 years ago

Oh nice you found it!