React Refs in a glance
2021-04-24
React interview cheatsheet series
React Refs provide a way to access DOM nodes or React elements created in the render method.
In the regular dataflow, props are the way that parent components interact with their children, so modifying a child component, you re-render it with new props. But sometimes, you don't want to modify a child inside the flow, but an instance of a component, or the DOM of a component For these cases are used the Refs.
For example, using Refs when you need to point to the DOM given by a component in order to make oprations in the UI with it, for example absolute positioning it into the screen, or make an animation or forcing a focus state, in these case, having a direct reference to that node element to modify it imperatively, is really useful.
The ref attibute is String type.
React 16.3 introduced React.createRef() but also, we can use the hook useRef()
React.createRef() in a Class Component
Given this example:
1class App extends React.Component { 2 constructor(props) { 3 super(props); 4 this.myTextInputRef = React.createRef(); 5 this.myHighlightTextRef = React.createRef(); 6 } 7 8 forceFocus = () => { 9 this.myTextInputRef.current.focus(); 10 this.myHighlightTextRef.current.className = "highlight"; 11 } 12 13 render() { 14 return ( 15 <div> 16 <p> 17 <span ref={this.myHighlightTextRef}>Click to focus the button and highlight this text using Refs:</span> 18 </p> 19 <p> 20 <input type="text" ref={this.myTextInputRef} /> 21 </p> 22 <p> 23 <button onClick={this.forceFocus}>Click me!</button> 24 </p> 25 </div> 26 ); 27 } 28} 29 30ReactDOM.render( 31 <App />, 32 document.getElementById('root') 33);
Link to the codepen.
The logic is the following:
- In the constructor we assign the Ref with React.createRef():
this.myTextInputRef = React.createRef();
- In the render method we set the ref with the ref atribute:
<input type="text" ref={this.myTextInputRef} />
- And finally, when a ref has been passed to an element in the render, the reference to the node becomes accessible at the current attribute of the ref:
this.myTextInputRef.current.focus();
useRef() Hook
Of course we can use React Refs in functional programming using the useRef hook.
The previous code would be equivalent to:
1const { useRef } = React 2 3function App() { 4 const myTextInputRef = useRef(); 5 const myHighlightTextRef = useRef(); 6 7 forceFocus = () => { 8 myTextInputRef.current.focus(); 9 myHighlightTextRef.current.className = "highlight"; 10 } 11 12 return ( 13 <div> 14 <p> 15 <span ref={myHighlightTextRef}>Click to focus the button and highlight this text using Refs:</span> 16 </p> 17 <p> 18 <input type="text" ref={myTextInputRef} /> 19 </p> 20 <p> 21 <button onClick={forceFocus}>Click me!</button> 22 </p> 23 </div> 24 ); 25}; 26 27ReactDOM.render( 28 <App />, 29 document.getElementById('root') 30);
But... What happen if we want to access to a ref from another component?
To do that, we need to wrap the component with React.forwardRef which allows to the wrapped component getting a reference and pass to its children, so the example above would be:
1const { useRef } = React 2 3function App() { 4 const myTextInputRef = useRef(); 5 const myHighlightTextRef = useRef(); 6 const ExternalHighlightTextRef = useRef(); 7 8 forceFocus = () => { 9 myTextInputRef.current.focus(); 10 myHighlightTextRef.current.className = "highlight"; 11 ExternalHighlightTextRef.current.className = "highlight"; 12 } 13 14 return ( 15 <div> 16 <p> 17 <span ref={myHighlightTextRef}>Click to focus the button and highlight this text using Refs:</span> 18 </p> 19 <p> 20 <input type="text" ref={myTextInputRef} /> 21 </p> 22 <p> 23 <button onClick={forceFocus}>Click me!</button> 24 </p> 25 26 <JustAComponent ref={ExternalHighlightTextRef} /> 27 </div> 28 ); 29}; 30 31// note as we pass ref as second parameter 32const JustAComponent = React.forwardRef((props, externalRef) => 33 <p><span ref={externalRef}>This is an external component refered from the parent one.</span></p> 34); 35 36ReactDOM.render( 37 <App />, 38 document.getElementById('root') 39);
See codepen