Typically in React we want to keep logic within components and preserve unidirectional data flow. However that’s not always possible, and sometimes we need to access the DOM element itself. This is where refs
come in.
In this article, we’ll cover a general overview of refs
, how to create them, and attaching them to custom components using forwardRef
. We will also use the useRef()
hook rather than the older createRef()
method. Ready? Let’s dive into it.
What are refs?
Refs
provide a way to access and interact with the DOM or React elements directly. They allow you to perform a variety of actions such as focusing, trigging animations, calculating size or position, or interacting with third-party libraries that need direct access to DOM elements.
To create a ref
, we call the useRef()
hook within a component. This creates a plain JavaScript object that holds the element in the current property. We can then attach it to a component to have access to it later.
We could use vanilla JavaScript to access components directly, but this is not recommended. It is also bad practice in React to directly access the DOM.
What is forwardRef?
React provides the higher-order component forwardRef
to pass a ref
from a parent component to a child component. It accepts a component as an argument and returns a new component.
forwardRef
is useful when you need to access or manipulate custom child components. Typically, passing ref
as a prop will not work and will result in an error. The ref
will point to the wrapper component rather than the element itself, resulting in the ref
being null. See the console in example below.
At Gravity Forms we use forwardRef
for our custom components. We build our components mainly for our own apps, but we also have a community of developers who extend our code and use it for their own plugins. Because of this, we build them to be flexible and allow our components to handle ref
forwarding.
Passing the ref
Now that we understand what ref
and forwardRef
are, we are now ready to use them.
First we’ll create a custom input component. We won’t worry too much about the complexities of the input, we’ll just pass the props straight through to the input element. Then we’ll wrap the input component in forwardRef
and add ref
as a second argument to the functional component.
Next, let’s create an App component that uses the custom input component. We will also create a ref
by calling useRef()
within the App component and pass it to the input. Finally, we’ll add a button element to the App component that focuses on the input when it is clicked.
Putting it all together, it’ll look something like below. When we click on the button, it grabs the ref
of the input component and focuses on it.
This is a very simple example, but we can use this same pattern to do more complex DOM manipulations.
When not to use refs
Refs
are a powerful tool. It allows developers to access React DOM elements directly and interact with them. However, there are some situations where refs
are likely not the right solution. This is not an exhaustive list, but illustrate a general pattern for data flow.
Manipulating state
Refs
are not ideal for managing UI state within React components. Rather, use the useState()
hook within the component or a centralized state management library such as Redux to manage app state. This supports the unidirectional data flow concept of React and allows data flow to be more predictable and maintainable.
Styling and CSS
Instead of styling components through refs
, it is better to use one of the various libraries for styling components, such as CSS-in-JS or CSS modules. These solutions allow for a more modular and maintainable approach to building components and apps.
Data fetching and side effects
Refs
should not be used to handle data fetching or side effects in components. React provides the useEffect()
hook to manage data fetching, subscriptions, and other side effects. Using this hook ensures proper synchronization and cleanup of resources within the component.
Wrapping it up
Refs
expand the possibilities for developing in React. However, they should be used carefully. Combining refs
with forwardRef
allows for more control over custom components, providing yet another tool for developers to use. Now that you know how to use it, go ahead and incorporate forwardRef
into your projects and take your components to the next level!