React is a library for creating front end views. It has a large ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.
To manipulate DOM elements directly with React, we can create a ref
, associate it to an element, and then reference that and call its methods to manipulate the DOM item directly.
In this article, we’ll look at how to pass the ref to components outside of its originating component by forwarding refs.
Forwarding refs to DOM components
We can forward refs by creating a ref and then call the forwardRef
method to get the ref and then pass it into any place we want.
For example, if we have a Button
component that returns a button
element, and we want to get the button
element from the outside component, we can write the following:
const Button = React.forwardRef((props, ref) => (
<button id="custom-button" ref={ref}>
{props.children}
</button>
));
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.buttonRef = React.createRef();
} componentDidMount() {
this.buttonRef.current.focus();
} render() {
return <Button ref={this.buttonRef}>Click Me</Button>;
}
}
In the code above, we have a Button
component created by using the React.forwardRef
method with a callback passed in.
The callback has a props
parameter which has the props that are passed in from the parent component, and the ref
object which has the ref that’s passed in from the parent component.
Then we set the ref
prop of the button
element to the ref
from the parameter.
Then we can create a new ref in the App
component by calling React.createRef
in App
‘s constructor. Then we pass that into the ref
prop of Button
so that we can access the ForwardRef from the button
element.
This means the this.buttonRef
is referencing the button
element because we passed it into Button
, which passes this.buttonRef
into the button
element via the callback we passed into React.forwardRef
.
Then in the App
component, we call:
this.buttonRef.current.focus();
in componentDidMount
to focus the button
in Button
from App
.
Forwarding refs in Higher-Order Components
We can also forward refs in high-order components. To do this, we write something like the following:
const Button = ({ forwardedRef, children }) => (
<button ref={forwardedRef}>{children}</button>
);
function logProps(Component) {
class LogProps extends React.Component {
componentDidMount() {
console.log(this.props);
}
render() {
const { forwardedRef, ...rest } = this.props;
return <Component forwardedRef={forwardedRef} {...rest} />;
}
}
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
}
class App extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}
componentDidMount() {
this.buttonRef.current.focus();
}
render() {
const ButtonLogProp = logProps(Button);
return <ButtonLogProp ref={this.buttonRef}>Click Me</ButtonLogProp>;
}
}
In the code above, we have the logProps
higher-order component. The logProps
component takes a Component
.
logProps
return a component with the forwarded refs passed in by calling React.forwardRef
with a callback that returns LogProps
.
In the App
component we pass this.buttonRef
as the value to ButtonLogProp
.
ButtonLogProp
is created by calling logProps
with the Button
component passed in. This means Component
is Button
in logProp
.
Component
, which is Button
is then returned in the render
method of the LogProp
component.
At the end of the logProp
higher-order component, we return the component with returned from React.forwardRef
. The callback we pass into forwardRef
returns the LogProps
component with the props including the forwarded ref passed in.
All the props will then reach the Button
component, which sets the ref
of the button
element to the this.buttonRef
, which is first passed into logProp
, then passed into LogProp
, and React.forwardRef
returns a component with the forwarded ref passed to the Button
component, and then into the button
element.
In other words, we passed the ref from App
, to logProp
, to LogProp
, then forwarded with React.forwardRef
to Button
and then to button
.
Conclusion
We can use refs from external components by forwarding refs. This lets us manipulate DOM elements from external components within a component.
Forwarding refs also works with higher-order components. All we have to do is to return the component we want to return in the higher-order component in the React.forwardRef
callback with the forwarded ref passed in.