Update: my problem was actually due to typos – the general approach works fine if you'd like to use a child element ref in both a child and parent component.
Here's a working example of the approach that works: https://codesandbox.io/s/rwj7z7o7oo
Original post:
I'm trying to forward a ref to the parent component, while also making the ref accessible for functions in the child (which is a class). Currently, I can successfully pass the ref to the parent, but the ref is no longer accessible in the child.
class Child extends React.Component {
// Unable to access the forwarded ref here:
componentDidMount() {
console.log(this.props.forwardedRef); // null
}
render() {
return <input type="text" ref={this.props.forwardedRef} />
}
}
// Parent is able to access the ref:
const Parent = () => {
const childRef = useRef(null);
function handleClick() {
console.log(childRef.current); // correctly ref's the input el
}
return (
<Child forwardedRef={childRef} onClick={handleClick} />
);
}
Is there another approach will let me use the ref in both Child and Parent?
There is one caveat to the above example: refs will not get passed through. That's because ref is not a prop. Like key , it's handled differently by React. If you add a ref to a HOC, the ref will refer to the outermost container component, not the wrapped component.
We should not use ref attribute on function components because they do not have instances. React will assign the current property with Dom element when component mount and assign null to it when component unmount. ref updates happen before componentDidMount or componentDidUpdate methods.
Accessing Refs When we assign a ref to an element or child component in the render, then we can access the element using the current attribute of the ref. const element = this. myRef.
useRef
returns values that are like instance variables classes. In your case, there is nothing that would cause the component to render even if your set the ref and hence componentDidUpdate of child wouldn't run.
Also you haven't returned anything from Child component.
class Child extends React.Component {
// Unable to access the forwarded ref here:
componentDidUpdate(prevProps) {
console.log(this.props.forwardedRef); // null
console.log(prevProps.forwardedRef); // null
}
render() {
return (
<React.Fragment>
<input type="text" ref={this.props.forwardedRef} />
<div>{this.props.count}</div>
<input type="button" onClick={this.props.onClick} value={"Click"} />
</React.Fragment>
);
}
}
// Parent is able to access the ref:
const Parent = () => {
const childRef = useRef(null);
const [count, setCount] = useState(0);
function handleClick() {
console.log(childRef.current); // correctly ref's the input el
setCount(count => count + 1);
}
return <Child forwardedRef={childRef} count={count} onClick={handleClick} />;
};
Working demo
No need to pass forwardedRef
in React hooks.
You can access ref
variable directly in forwardRef
function:
const Child = React.forwardRef((_props, ref) => {
React.useLayoutEffect(() => {
if (ref.current) {
ref.current.insertAdjacentHTML(
"beforeend",
"<span>Ref works in child</span>"
);
}
}, [ref]);
return (
<div className="child" ref={ref}>
<h2>Child Component</h2>
</div>
);
});
const Parent = () => {
const childRef = React.useRef(null);
React.useLayoutEffect(() => {
if (childRef.current) {
childRef.current.insertAdjacentHTML(
"afterbegin",
"<span>Ref works in parent</span>"
);
}
}, []);
return (
<div className="parent">
<h1>Parent Component</h1>
<Child ref={childRef} />
</div>
);
};
function App() {
return (
<div className="App">
<Parent />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<App />,
rootElement
);
.App {
font-family: sans-serif;
text-align: center;
padding: 1rem;
}
.parent {
border: 1px dashed red;
padding: 1rem;
}
.child {
border: 1px dashed blue;
padding: 1rem;
}
span {
display: block;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
margin: 0.5rem;
color: #777;
border: 1px dashed #999;
}
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
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