I am using a react-mui library in my project where I would like to implement a MenuList
ponent, found under MenuList position here. In my application though I am sending a ref
as prop
down to a child ponent
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 ponent 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 ponent that has a menu button:
<MenuButton
className={classes.button}
handleToggle={handleToggle}
setRef={setRef}
open={open}
ref={ref}
/>
Then the Popper ponent 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
ponent where I would avoid sending down ref
as a prop
?
I am using a react-mui library in my project where I would like to implement a MenuList
ponent, found under MenuList position here. In my application though I am sending a ref
as prop
down to a child ponent
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 ponent 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 ponent that has a menu button:
<MenuButton
className={classes.button}
handleToggle={handleToggle}
setRef={setRef}
open={open}
ref={ref}
/>
Then the Popper ponent 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
ponent where I would avoid sending down ref
as a prop
?
2 Answers
Reset to default 7ref
is a keyword in reactjs. When you use ref
as a prop it linked the ponent to the ref object. Rename it to whatever you like on FancyButton
ponent and MenuListComposition
ponent.
From react documentation.
React supports a special attribute that you can attach to any ponent.
Working example with ref renamed to parentRef in both ponents.
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 monly assigned to an instance property when a ponent is constructed so they can be referenced throughout the ponent. Moreover, When a ref is passed to an element in render, a reference to the node bees accessible at the current attribute of the ref.
React provides method React.forwardRef to pass refs in the ponent hierarchy. This is typically not necessary for most ponents in the application. However, it can be useful for some kinds of ponents, especially in reusable ponent 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>;