If I have something like
And I want to access from
Here is an example that will focus on an input using refs (tested in React 16.8.6):
The Child component:
class Child extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return (<input type="text" ref={this.myRef} />);
}
}
The Parent component with the Child component inside:
class Parent extends React.Component {
constructor(props) {
super(props);
this.childRef = React.createRef();
}
componentDidMount() {
this.childRef.current.myRef.current.focus();
}
render() {
return <Child ref={this.childRef} />;
}
}
ReactDOM.render(
<Parent />,
document.getElementById('container')
);
The Parent component with this.props.children:
class Parent extends React.Component {
constructor(props) {
super(props);
this.childRef = React.createRef();
}
componentDidMount() {
this.childRef.current.myRef.current.focus();
}
render() {
const ChildComponentWithRef = React.forwardRef((props, ref) =>
React.cloneElement(this.props.children, {
...props,
ref
})
);
return <ChildComponentWithRef ref={this.childRef} />
}
}
ReactDOM.render(
<Parent>
<Child />
</Parent>,
document.getElementById('container')
);
Using Ref forwarding you can pass the ref from parent to further down to a child.
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
Note The second ref argument only exists when you define a component with React.forwardRef call. Regular functional or class components don’t receive the ref argument, and ref is not available in props either.
Ref forwarding is not limited to DOM components. You can forward refs to class component instances, too.
Reference: React Documentation.
If it cannot be avoided the suggested pattern extracted from the React docs would be:
import React, { Component } from 'react';
const Child = ({ setRef }) => <input type="text" ref={setRef} />;
class Parent extends Component {
constructor(props) {
super(props);
this.setRef = this.setRef.bind(this);
}
componentDidMount() {
// Calling a function on the Child DOM element
this.childRef.focus();
}
setRef(input) {
this.childRef = input;
}
render() {
return <Child setRef={this.setRef} />
}
}
The Parent forwards a function as prop bound to Parent's this
. When React calls the Child's ref
prop setRef
it will assign the Child's ref
to the Parent's childRef
property.
Ref forwarding is an opt-in feature that lets some components take a ref they receive, and pass it further down (in other words, “forward” it) to a child.
We create Components that forward their ref
with React.forwardRef
.
The returned Component ref prop must be of the same type as the return type of React.createRef
. Whenever React mounts the DOM node then property current
of the ref
created with React.createRef
will point to the underlying DOM node.
import React from "react";
const LibraryButton = React.forwardRef((props, ref) => (
<button ref={ref} {...props}>
FancyButton
</button>
));
class AutoFocus extends React.Component {
constructor(props) {
super(props);
this.childRef = React.createRef();
this.onClick = this.onClick.bind(this);
}
componentDidMount() {
this.childRef.current.focus();
}
onClick() {
console.log("fancy!");
}
render() {
return <LibraryButton onClick={this.onClick} ref={this.childRef} />;
}
}
Created Components are forwarding their ref
to a child node.
function logProps(Component) {
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log('old props:', prevProps);
console.log('new props:', this.props);
}
render() {
const {forwardedRef, ...rest} = this.props;
// Assign the custom prop "forwardedRef" as a ref
return <Component ref={forwardedRef} {...rest} />;
}
}
// Note the second param "ref" provided by React.forwardRef.
// We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
// And it can then be attached to the Component.
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
See Forwarding Refs in React docs.
/*
* Child component
*/
class Child extends React.Component {
render() {
return (
<div id="child">
<h1 ref={(node) => { this.heading = node; }}>
Child
</h1>
</div>
);
}
}
/*
* Parent component
*/
class Parent extends React.Component {
componentDidMount() {
// Access child component refs via parent component instance like this
console.log(this.child.heading.getDOMNode());
}
render() {
return (
<div>
<Child
ref={(node) => { this.child = node; }}
/>
</div>
);
}
}
Demo: https://codepen.io/itsfadnis/pen/aLWVVx?editors=0011
I think this guide explains it pretty well https://github.com/yannickcr/eslint-plugin-react/issues/678
class Field extends Component {
const { inputRef } = this.props;
render() {
return (
<input type="text" ref={inputRef} />
)
}
}
class MyComponent extends Component {
componentDidMount() {
this.inputNode.focus();
}
render() {
return (
<div>
Hello, <Field inputRef={node => this.inputNode = node} />
</div>
)
}
}
First access the children with: this.props.children
, each child will then have its ref
as a property on it.