Manipulating the DOM with Refs Flashcards
Manipulating the DOM with Refs
React automatically updates the DOM to match your render output, so your components won’t often need to manipulate it.
However, sometimes you might need access to the DOM elements managed by React—for example, to focus a node, scroll to it, or measure its size and position.
There is no built-in way to do those things in React, so you will need a ref to the DOM node.
Getting a ref to the node
To access a DOM node managed by React, first, import the useRef Hook.
Then, use it to declare a ref inside your component.
Finally, pass it to the DOM node as the ref attribute
When React creates a DOM node for this <div>, React will put a reference to this node into myRef.current. You can then access this DOM node from your event handlers and use the built-in browser APIs defined on it.
// You can use any browser APIs, for example: myRef.current.scrollIntoView();</div>
Accessing another component’s DOM nodes and Forward Refs
When you put a ref on a built-in component that outputs a browser element like , React will set that ref’s current property to the corresponding DOM node (such as the actual in the browser).
However, if you try to put a ref on your own component, like , by default you will get null.
This happens because by default React does not let a component access the DOM nodes of other components. Not even for its own children! This is intentional. Refs are an escape hatch that should be used sparingly. Manually manipulating another component’s DOM nodes makes your code even more fragile.
Instead, components that want to expose their DOM nodes have to opt in to that behavior. A component can specify that it “forwards” its ref to one of its children. Here’s how MyInput can use the forwardRef API:
const MyInput = forwardRef((props, ref) => { return ; });
- tells React to put the corresponding DOM node into inputRef.current. However, it’s up to the MyInput component to opt into that—by default, it doesn’t.
- The MyInput component is declared using forwardRef. This opts it into receiving the inputRef from above as the second ref argument which is declared after props.
- MyInput itself passes the ref it received to the inside of it.
A component doesn’t expose its DOM nodes by default. You can opt into exposing a DOM node by using forwardRef and passing the second ref argument down to a specific node.
When React attaches the refs
In React, every update is split in two phases:
- During render, React calls your components to figure out what should be on the screen.
- During commit, React applies changes to the DOM.
In general, you don’t want to access refs during rendering. That goes for refs holding DOM nodes as well. During the first render, the DOM nodes have not yet been created, so ref.current will be null. And during the rendering of updates, the DOM nodes haven’t been updated yet. So it’s too early to read them.
React sets ref.current during the commit. Before updating the DOM, React sets the affected ref.current values to null. After updating the DOM, React immediately sets them to the corresponding DOM nodes.
Usually, you will access refs from event handlers. If you want to do something with a ref, but there is no particular event to do it in, you might need an effect.
Best practices for DOM manipulation with refs
Refs are an escape hatch. You should only use them when you have to “step outside React.” Common examples of this include managing focus, scroll position, or calling browser APIs that React does not expose.
If you stick to non-destructive actions like focusing and scrolling, you shouldn’t encounter any problems. However, if you try to modify the DOM manually, you can risk conflicting with the changes React is making.
Avoid changing DOM nodes managed by React. Modifying, adding children to, or removing children from elements that are managed by React can lead to inconsistent visual results or crashes like above.
However, this doesn’t mean that you can’t do it at all. It requires caution. You can safely modify parts of the DOM that React has no reason to update. For example, if some <div> is always empty in the JSX, React won’t have a reason to touch its children list. Therefore, it is safe to manually add or remove elements there.
Avoid changing DOM nodes managed by React.
If you do modify DOM nodes managed by React, modify parts that React has no reason to update.</div>