javascriptreactjsmaterial-uireact-ref

React - sending down ref as a prop not working


I am using a react-mui library in my project where I would like to implement a MenuList component, found under MenuList composition here. In my application though I am sending a ref as prop down to a child component where I have a menu. You can see the codesandbox example here. When I send a ref and a setRef method as props from a parent component like this:

state = {
    open: false,
    ref: React.createRef()
  };

  setRef = element => {
    this.setState({ ref: element });
  };

  handleToggle = () => {
    this.setState(state => ({ open: !state.open }));
  };

  handleClose = () => {
    this.setState({ open: false });
  };

  render() {
    return (
      <MenuListComposition
        setRef={this.setRef}
        handleToggle={this.handleToggle}
        handleClose={this.handleClose}
        open={this.state.open}
        ref={this.state.ref}
      />
    );
  }

To a child component that has a menu button:

    <MenuButton
      className={classes.button}
      handleToggle={handleToggle}
      setRef={setRef}
      open={open}
      ref={ref}
   />

Then the Popper component which has a menu list opens at a wrong place, which you can see in the codesanbox example if you click on the TOGGLE MENU GROW button.

      <Popper open={open} anchorEl={ref} transition disablePortal>
          {({ TransitionProps, placement }) => (
            <Grow
              {...TransitionProps}
              id="menu-list-grow"
              style={{
                transformOrigin:
                  placement === "bottom" ? "center top" : "center bottom"
              }}
            >
              <Paper>
                <ClickAwayListener onClickAway={handleClose}>
                  <MenuList>
                    <MenuItem onClick={handleClose}>Profile</MenuItem>
                    <MenuItem onClick={handleClose}>My account</MenuItem>
                    <MenuItem onClick={handleClose}>Logout</MenuItem>
                  </MenuList>
                </ClickAwayListener>
              </Paper>
            </Grow>
          )}
        </Popper>

What am I doing wrong and how to fix this, or how can I use ref in a stateless component where I would avoid sending down ref as a prop?


Solution

  • ref is a keyword in reactjs. When you use ref as a prop it linked the component to the ref object. Rename it to whatever you like on FancyButton component and MenuListComposition component.

    From react documentation.

    React supports a special attribute that you can attach to any component.

    Working example with ref renamed to parentRef in both components.

    EDIT:

    As pointed it out by Vaibhav Shukla, you can use React.forwardRef on both FancyButton and MenuListComposition which is probably the correct way to do this.

    Working example