Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 977
Leff Avatar asked Oct 16 '25 19:10

Leff


2 Answers

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

like image 173
nubinub Avatar answered Oct 19 '25 09:10

nubinub


Ref cannot be passed like a prop in React. Refs are commonly assigned to an instance property when a component is constructed so they can be referenced throughout the component. Moreover, When a ref is passed to an element in render, a reference to the node becomes accessible at the current attribute of the ref.

React provides method React.forwardRef to pass refs in the component hierarchy. This is typically not necessary for most components in the application. However, it can be useful for some kinds of components, especially in reusable component libraries. Read about forwardRef

    const ButtonWrapper = React.forwardRef((props, ref) => (
      <button ref={ref}>
        {props.children}
      </button>
    ));

    // You can now get a ref directly to the DOM button:
    const ref = React.createRef();
    <ButtonWrapper ref={ref}>Click me!</ButtonWrapper>;
like image 23
Vaibhav Shukla Avatar answered Oct 19 '25 09:10

Vaibhav Shukla