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
?
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
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>;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With