Introduction
In the
previous article, we reviewed about Fragments and Pure Components in React and its usage. In this article, we will learn the concept of Memo and Ref in React and how it is used.
Memo
The concept named Memo is a function-based component, unlike Pure Component which is a class-based component. React.memo() is a higher-order component same as React.PureComponent(). It also provides a performance boost.
If the function component renders the same result using the same props, it can be wrapped in React.memo() for performance enhancement. This means that React will skip rendering the component and reuse the last rendered result.
By default React.memo() shallowly compares the objects in the props object. If it is required to control comparison or any custom comparison, we can pass a function in the second argument.
Before looking at the example, we must ensure from the package.json file that it is React version 16.6 or higher.
Let's look at the example below.
Create a component for memo.js.
- import React from 'react';
- function MemoComp({name}){
- console.log("Memo component");
- return (
- <div>
- {name}
- </div>
- )
- }
-
- export default React.memo(MemoComp);
Now, add the memo component to parent component.
- import React,{Component} from 'react';
- import MemoComp from './Calculation';
-
- class ParentComponent extends Component{
- constructor(props){
- super(props);
- this.state={
- name : 'React'
- }
- }
-
- componentDidMount(){
- setInterval(()=>{
- this.setState({
- name:'React'
- })
- },2000)
- }
-
- render(){
- console.log('rendered parent');
- return(
- <div>
- Parent Component
- <MemoComp name= {this.state.name}/>
- </div>
- )
- }
- }
-
- export default ParentComponent;
Add this parent component in App.js. Now, see the result in the browser.
As you can see in the console, the memo component is rendered once and after that, it is not rendered until any changes occur in props or state.
So, it is the same as Pure component irrespective of the fact that Pure component is used for class component and memo components are used for functional component.
Refs
Refs in React make it possible to access DOM nodes directly without using props or re-rendering a whole component.
Let’s look at an example to change the input element without using props.
- import React, { Component } from 'react'
-
- class RefsDemo extends Component {
- constructor(props) {
- super(props);
- this.inputRef = React.createRef()
- }
-
- componentDidMount(){
- this.inputRef.current.focus();
- console.log(this.inputRef)
- }
-
- clickHandler = () => {
- alert(this.inputRef.current.value)
- }
-
- render() {
- return (
- <div>
- <input type="text" ref={this.inputRef}/>
- <button onClick={this.clickHandler}>Click Me!</button>
- </div>
- )
- }
- }
-
- export default RefsDemo
The above image defines the 3 steps to use Refs for inputting an element.
The first step involves creating Ref; the second step includes accessing Ref in the input element, and the third step includes accessing the value of Ref.
In the above example, we have seen how an input text is used as Ref and how its value can be accessed. This is one of the ways to create and use Refs.
Another way to use Ref is a callback approach which is considered an old approach.
Let's see a demo with callback Ref.
- import React, { Component } from 'react'
-
- class RefsDemo extends Component {
- constructor(props) {
- super(props);
- this.inputRef = React.createRef()
- this.callbackRef = null
- this.setCallbackRef = (element) => {
- this.callbackRef = element
- }
- }
-
- componentDidMount(){
- if(this.callbackRef){
- this.callbackRef.focus()
- }
- }
-
- clickHandler = () => {
- alert(this.inputRef.current.value)
- }
-
- render() {
- return (
- <div>
- <input type="text" ref={this.inputRef}/>
- <input type="text" ref={this.setCallbackRef}/>
- <button onClick={this.clickHandler}>Click Me!</button>
- </div>
- )
- }
- }
-
- export default RefsDemo
For callback Refs, we need to follow the following four steps.
-
First, create a Ref and assign it the null value.
-
Second, create a method to assign DOM elements to the Ref created in the first step.
-
The third step is to assign setCallbackRef method to the input element
-
Fourth, access in componentDidMount, but in this method, we need to make sure that React will call the callback when component mounts and call it null when the component is unmounted so it is necessary to check if value exists in callbackRef property and is not null.
The output for callback will be same as CreateRef,
Refs with class component
As we saw about adding Ref in the input element, we can also add Ref to the class component.
Let's create a InputRef component,
- import React, { Component } from 'react'
-
- export class InputRef extends Component {
- constructor(props) {
- super(props)
- this.inputRef = React.createRef();
- }
-
- focusInput(){
- this.inputRef.current.focus()
- }
-
- render() {
- return (
- <div>
- <input type="text" ref={this.inputRef}/>
- </div>
- )
- }
- }
-
- export default InputRef
Now create a FocusInput.js and import InputRef
- import React, { Component } from 'react'
- import InputRef from './InputRef'
-
- class FocusInput extends Component {
- constructor(props) {
- super(props)
- this.componentRef = React.createRef()
- }
-
- clickHandler = () =>{
- this.componentRef.current.focusInput()
- }
-
- render() {
- return (
- <div>
- <InputRef ref={this.componentRef}/>
- <button onClick={this.clickHandler}>Focus Input</button>
- </div>
- )
- }
- }
-
- export default FocusInput
Now add FocusInput.js in App,js
- import React from 'react';
- import logo from './logo.svg';
- import './App.css';
- import FocusInput from "./components/FocusInput"
-
- function App() {
- return (
- <div className="App">
- <header>
- <img src={logo} className="App-logo" alt="logo" />
- </header>
- <FocusInput></FocusInput>
- </div>
- );
- }
-
- export default App;
The output will be as shown below.
On button click, input element will get focus which is defined in the child component.
The Ref component can also use child component. But Ref can never be attached with the functional component. Only a class component can use Refs.
When Refs should be used
-
When required to focus on the text, text selection or playback media.
-
Triggering animations.
-
Integrating with third-party DOM libraries.
When you need to do anything complex in your app then Refs should not be used.
Forwarding Ref
Ref forwarding is a technique for passing a ref through the component to one of its child components. This technique is mainly useful for HOC (Higher Order Components).
React.forwardRef() accepts 2 parameters - the props of the parameter we are wrapping and ref object specifically for the ref we are forwarding.
Let’s look at the example below, create a component named FRInput.js
- import React, { Component } from 'react'
- const FRTextInput = React.forwardRef((props,ref) => {
- return(
- <div>
- <input type="text" ref={ref}/>
- </div>
- )
- })
-
- export default FRTextInput
And include FRInput to FRParent.js component,
- import React, { Component } from 'react'
- import FRTextInput from './FRTextInput'
-
- class FRParent extends Component {
- constructor(props) {
- super(props)
-
- this.inputRef = React.createRef()
- }
-
- render() {
- return (
- <div>
- <FRTextInput ref={this.inputRef}/>
- </div>
- )
- }
- }
-
- export default FRParent
Here, you can see the created inputRef in ParentRef is passed to InputRef where it is used in the input element.
The output will be displayed as below.
Now on click of the button, the focus will be set on the text input.
The process of forwardRef is as below.
-
To be able to pass a ref into a component wrapped into the HOC via a forwardRef prop
-
The HOC to take a ref and forward it to the wrapped component.
-
The wrapped component to attach the ref to a child element.
Summary
In this article, we learned the concept of memo and Ref and 2 ways to use Ref in React. Then, we created Ref and Callback Ref approach in React and learned the concept of forwardRef in React. In the next article, we will learn about React portal and Error Boundary.