HomeBlogWeb DevelopmentReact useRef: What is UseRef in React?

React useRef: What is UseRef in React?

Published
05th Sep, 2023
Views
view count loader
Read it in
12 Mins
In this article
    React useRef: What is UseRef in React?

    Web developers work with many programming languages, libraries, and frameworks like React, Angular, Vue, Next, etc. They have changed how we used to interact with the DOM for building websites and applications as now everything is component-based, a built-in feature that these frameworks and libraries provide us. If you are unsure how they change how we interact with the DOM nodes, learn React online with us, where we have provided a specialized course just to get you started with React. 

    But there are still many times when we have to interact directly with DOM for some native behavior that we want our apps to have and many a time we prefer using the APIs for that which are also built-in features provided by these frameworks like useState and useReducer which are used for managing local states in React 

    These hooks are great and are widely used for managing the local states, but at the cost of being called too often and re-rendering the component every time, they are called to update the function which can sometimes affect the performance of a component. In this blog, we will explain how we can directly interact with DOM to make those native behaviors that we want our apps to have, without re-rendering or calling any API for that matter, with the help of a popular hook useRef. 

    What is useRef Hook?

    As told above, useRef is a hook introduced with other hooks in React version 16.8 and is mainly used for creating a reference of the DOM element or directly accessing it inside a functional component. 

    But don't think even for a second that it's the only thing this hook is capable of as it can even be used for storing mutable values across different rerenders of the component. 

    Like every other hook in React, we have to first import this hook at the very top level as per the rules of hooks and then only we can use it in our apps. 

    import { useRef } from "react"; 
    const reference = useRef("initial value"); 

    Unlike other hooks like useState which returns two values, the state and a function, this hook returns a mutable ref object which will carry the value throughout the component and if any change is made in the component, the updated value will be carried forward across our React component. 

    This object has a property called current which will initially contain the value with which we have initialized the component. 

    { 
    current: "initial value"; 
    } 
    Let's see useRef in action.
    import React, { useState } from "react"; 
    const child = { 
    padding: "25px", 
    margin: "25px", 
    border: "2px solid blue", 
    }; 
    export const Practice = (prop) => { 
    console.log("function called...."); 
    let counter = 0; 
    let [myState, setMyState] = useState(0); 
    let updateState = () => { 
    counter++; 
     setMyState(myState + 1); 
    console.log("counter: " + counter); 
    }; 
    return ( 
    <div style={child}> 
    <div> 
    <div>MyState : {myState}</div> 
    <input 
    type="button" 
    onClick={() => updateState()} 
    value="Update State" 
    ></input> 
    </div> 
    </div> 
    ); 
    }; 

    Here we have made a counter app in which we have a counter whose value increases as we click on the update function button, which triggers the function using the onClick event handler and increases the value of the encounter by one.

    But here is a problem, with every state change, the value of the counter gets increased on our screen, but the counter we made as an instance of the app and displayed its result in the console will stay at 1. This is because the whole app gets re-rendered with every state change making the value of the counter of the console restart with zero every time.

    Now let's modify this instance variable using useRef. And now, the same returned object will always be used and stay closed to the Component for the full lifetime of the component as all the mutable ref values will persist with every render.


    useRef doesn’t notify us when its content changes. Mutating the .current property doesn’t cause a re-render. If we want to run some code when React attaches or detaches a ref to a DOM node, a callback ref is better suited. 

    What are Refs in React?

    In the above section, we saw a word many times, ‘refs.’ In this section, we will talk a little about refs. Refs are also a feature provided to us by React in its 16.3 version. At that time due to the unavailability of hooks, it can only be used in class components using the React.createRef component. But what exactly are refs? 

    According to the official documentation, “In a typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to modify a child imperatively outside the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch Ref.” 

    The above statement means that with the help of refs we can have direct access to React elements and not just DOM nodes and that we don’t always need the props or the state to modify the child component. 

    Generally, refs are used when the interaction between either React element or DOM nodes cannot be achieved using the mechanisms of state and prop. But there are some scenarios where we have to use refs to get the work done, and there are also some scenarios where using a ref can cause trouble for the app. 

    When to Use Refs

    There are only three possibilities when we can use Refs in our component -

    • Managing focus, text selection, or media playback. 
    • Integrating with third-party DOM libraries. 
    • Triggering imperative animations. 

    We can use the ref attribute to access the DOM API. We can get the value of an input element and, at the same time, trigger methods like a focus() with it. See the code below. 

    import "./styles.css"; 
    import { 
    useRef 
    } from "react"; 
    const App = () => { 
    const inputElement = useRef(); 
    const focusInput = () => { 
    inputElement.current.focus(); 
    }; 
    return ( < 
    > 
    < 
    input type = "text" 
    ref = { 
    inputElement 
    } 
    /> < 
    button onClick = { 
    focusInput 
    } > Focus Input < /button> < / 
    > 
    ); 
    } 
    export default App; 

    Source code  

    We can use it to integrate our React App with third-party libraries like D3.js as it has to be hooked into the DOM of the React App, which has its own DOM manipulation API.

    And lastly, to trigger animations in our App as sometimes we want the animation to stay as it is, even if we make any changes to our app 

    When Not to Use Refs

    Well, TRY TO AVOID REFS AS MUCH AS POSSIBLE.

    Though it might be tempting at first, try sticking to the old state and props for state management and other stuff as they keep the code clean and easier to debug. And use Refs only when you are unable to interact with DOM nodes or React Elements using both state and props; otherwise, avoid using them. 

    Creating Refs in React

    Creating Refs was only allowed in class components as functional components do not have instances for refs to attach themselves, so most of the code we will see after this will be of class-based components. 

    The main reason behind this is that with refs, we will only get the reference or instance of that element rather than the element itself, or in the case of DOM, the node itself and, as we know functional components do not have instances. 

    Let’s see the different ways through which we can create refs in class components -

    1. String Refs - Legacy Method 
    2. Callback Refs 
    3. React.createRef - courtesy of React 16.3 
    4. useRef - courtesy of React Hooks 

    String Refs

    If anyone who is reading this blog has been using React for more than a couple of years, you might be familiar with an older API of React in which refs were ‘string,’ and the DOM nodes were used to be accessed like ‘this.refs.str’ where the ref is used as a prop. 

    And now, it is advised not to use this type of refs anymore as it has some mistakes which may make the React App slower, and because of that, it might be removed soon. 

    Let's understand this with an example. 

    In this example, we will toggle our text between upper and lowercase characters with the help of a button that says toggle text. 

    import React from "react"; 
    class App extends React.Component { 
    constructor(props) { 
     super(props); 
    this.toggleInputCase = this.toggleInputCase.bind(this); 
    this.state = { uppercase: false }; 
    } 
    toggleInputCase() { 
    const isUpper = this.state.uppercase; 
    // Accessing the ref using this.refs.inputField 
    const value = this.refs.inputField.value; 
    this.refs.inputField.value = isUpper 
    ? value.toLowerCase() 
    : value.toUpperCase(); 
    this.setState({ uppercase: !isUpper }); 
    } 
    render() { 
    return ( 
    <div> 
    {/* Creating a string ref named: inputField */} 
    <input type="text" ref="inputField" /> 
    <button type="button" onClick={this.toggleInputCase}> 
    Toggle Case 
    </button> 
    </div> 
    ); 
    } 
    } 
    export default App; 

    We had initialized the state of the component with an uppercase property initially set to false and a function with an onClick event handler set to the button which will toggle the text's font between uppercase and lowercase characters. 

    <input type="text" ref="inputField" /> 

    The main role is played by the ref attribute which we have created in the input field as shown, which contains the string this.ref.inputRef which is responsible for manipulating the DOM and toggling the input value. 

    import "./styles.css";
    
    export default function App() {
        return ( <
            div className = "App" >
            <
            h1 > Hello CodeSandbox < /h1> <
            h2 > Start editing to see some magic happen! < /h2> < /
            div >
        );
    }

    Source Code

    As told, this method has some issues while calling and using refs and does not give control over the refs and thus was discontinued and was taken over by callback red which in place of strings uses a callback function

    Callback Refs

    This is an alternate way of creating refs that gives us more control over the refs as this uses a callback function instead of a string to create refs as told above. 

    This callback function receives the React component instance or HTML DOM element as its argument, which can be stored and accessed elsewhere. Let's see how our code changes from when we were using string refs and now when we are using callback refs. 

    import React from "react"; 
    class App extends React.Component { 
    constructor(props) { 
     super(props); 
    this.toggleInputCase = this.toggleInputCase.bind(this); 
    this.state = { uppercase: false }; 
    } 
    toggleInputCase() { 
    const isUpper = this.state.uppercase; 
    // const value = this.refs.inputField.value; // String Ref 
    const value = this.inputField.value; 
    // this.refs.inputField.value = isUpper // String Ref 
    tshis.inputField.value = isUpper ? value.toLowerCase() : value.toUpperCase(); 
    this.setState({ uppercase: !isUpper }); 
    } 
    render() { 
    return ( 
    <div> 
    {/* <input type="text" ref="inputField" /> */}// string ref 
    <input type="text" ref={elem => this.inputField = elem} /> 
    {/* Creating a callback ref and storing it in this.inputField */} 
    <button type="button" onClick={this.toggleInputCase}> 
    Toggle Case 
    </button> 
    </div> 
    ); 
    } 
    } 
    export default App; 

    There are some important facts that we should know before using the callback refs as we did in the code above -

    1. 1. React will call the callback ref function with the DOM elements when the components mount. 
    2. 2. And with null when it unmounts.

    In the above code, we have not made any significant changes. The changes we have made are only the ones concerning the Refs like replacing the String Refs with the CallBack Refs. Like 

    1. In the input field

     <input type="text" ref="inputField" /> // String Refs 
    <input type="text" ref={elem => this.inputField = elem} /> // Callback refs 

    2. In the Event handler 

    const value = this.refs.inputField.value; // String Ref 
    const value = this.inputField.value; // CallBack Refs 

    These changes will not have any effect on the output of the code. It is just that using the callback Refs gives us more control over the Refs than we had with the string Refs. 

    If everything is clear, then it’s all good and you can proceed further with the blog, but if you are having trouble understanding things like the super keyword, constructor or anything else, we recommend you to take the React course learn React online by KnowledgeHut

    React.createRef 

    Starting from version 16.3, we have a new syntax for using refs for class-based components while functional-based components remain the same without any ability to create refs due to the unavailability of instances. 

    There is no such difference between callback refs and refs created with createRefs. The only difference we will see is in the syntax which is way shorter and cooler than both string and callback refs. 

    Let's see what changes we have to make in our previous app with this React.createRef method

    import React from "react"; 
    class App extends React. Component { 
    constructor(props) { 
     super(props); 
    this.inputField = React.createRef(); 
    this.toggleInputCase = this.toggleInputCase.bind(this); 
    this.state = { uppercase: false }; 
    } 
    toggleInputCase() { 
    const isUpper = this.state.uppercase; 
    // Accessing the ref using this.inputField.current 
    const value = this.inputField.current.value; 
    this.inputField.current.value = 
    isUpper 
    ? value.toLowerCase() 
    : value.toUpperCase(); 
    this.setState({ uppercase: !isUpper }); 
    } 
    render() { 
    return ( 
    <div> 
    {/* Referencing the ref from this.inputField */} 
    <input type="text" ref={this.inputField} /> 
    <button type="button" onClick={this.toggleInputCase}> 
    Toggle Case 
    </button> 
    </div> 
    ); 
    } 
    }
    export default App; 

     It is already clear from the code which parts have been updated to create refs using React.ceateRef, let’s still have a look at them. 

    1. In all of the above methods of creating refs, we have never created a ref in the constructor, but here we have created one 

    this.inputField = React.createRef(); 

    2. As always we have to change the methods in the event handler as we have done it for the above cases. 

    const value = this.inputField.current.value; 
    this.inputField.current.value = isUpper 
    ? value.toLowerCase() 
    : value.toUpperCase(); 

    This is worth noting for refs created with React.createRef(). The reference to the node becomes accessible at the current attribute of the ref just like the useRef Hook. 

    3. And lastly, in the input field

     <input type="text" ref={this.inputField} /> 

    Changing refs will not affect the output of the code it's just that with every change in the syntax, we are getting better control of the refs. 

    React useRef Hook 

    We have already discussed this hook and many of its features at the beginning of this blog. Now let’s see how we create Refs in our application using this hook. 

    Don't forget that we can only use hooks in react functional components and we can’t create refs in the same way we used to create them in class components here as functional components do not have instances to begin with, and not even this hook can change this fact. Then how are we creating refs in functional components? 

    Let's first modify our ongoing example of creating an input field and toggling the text we write in it between upper and lower case letters. 

    import React, { useState, useRef } from "react"; 
    const App = () => { 
    const [uppercase, setUppercase] = useState(false); 
    const inputField = useRef(null); 
    const toggleInputCase = () => { 
    // Accessing the ref using inputField.current 
    const value = inputField.current.value; 
    inputField.current.value = uppercase 
    ? value.toLowerCase() 
    : value.toUpperCase(); 
     setUppercase((previousValue) => !previousValue); 
    }; 
    return ( 
    <> 
    <div> 
    {/* Referencing the ref from this.inputField */} 
    <input type="text" ref={inputField} /> 
    <button type="button" onClick={toggleInputCase}> 
    Toggle Case 
    </button> 
    </div> 
    </> 
    ); 
    }; 
    export default App; 

    We are already well aware that this hook returns a mutable object with a value of .current equal to the initial value that we declared with, which in the above code is null. 

    The biggest thing to notice here is that the code is pretty much similar to the one we have written for React.createRef. The only difference is that this is written in a functional-based component. 

    Now to answer the question why are we still creating refs when functional components have no instances? The answer is very simple, every element in JSX has an optional ref property. If we pass a ref object to it (which we created with useRef), it gets updated to contain the HTML element. 

    If we log the inputField object, we'll see that it contains the DOM element: 

    We will understand this more in the upcoming sections. For now, just understand that every JSX element has an optional ref attribute which we can use to create a ref respective to an HTML element. 

    How to Access Refs

    We know that when a ref is passed to a node in render, an instance of that is created, stored, and can be accessed from the current attribute of the ref. But the value that is stored and becomes accessible changes depending on the type of node. Let’s see how. 

    1. Suppose the ref is used on an HTML element, like the ref attribute we keep accessing from the input tag in all of our above examples. In that case, the ref created in the constructor with React.createRef() receives the underlying DOM element as its current property which we have already seen in the above image. 

    2. If the ref attribute is used on a custom class component, the ref object receives a mounted instance of the component as its current. 

    We have already seen how to access refs from the DOM node when we're creating refs using React.createRef, we did use something like 

    this.inputField = React.createRef(); 
    <input type="text" ref={this.inputField} />; 

    Here we are using the ref attribute on the input tag, which is an HTML element, and keep accessing its value using the current property of the ref attribute. Now let's see how to access refs used in a custom class component, and for that, we will be using the toggle component only as a custom class component. 

    class AutoFocusTextInput extends React.Component { 
    constructor(props) { 
     super(props); 
    this.textInput = React.createRef(); 
    } 
    componentDidMount() { 
    this.textInput.current.focusTextInput(); 
    } 
    render() { 
    return <App ref={this.textInput} />; 
    } 
    } 

    Here we are just wrapping our App component with another class-based component so that as soon as our App mounts, we could use a ref to get access to the custom input and call its toggle method manually: 

    How to Store and Access Previous Values Using Refs 

    As we know, refs give us the ability to store a value that will persist across all renders, meaning it will not be affected by the re-rendering of the component and will get updated as soon we call the function responsible for updating its value. 

    We have also seen this in the very first example, where we have made a counter which keeps on increasing on the front part but at the back will remain stuck at 1. It is due to re-rendering which happens every time we click the button which calls the function and the count increase by one. 

    And when we did the same process but this time by creating an instance of it and updating that as well, we can see that the re-rendering of the component is not affecting it and it keeps on increasing

    And it also proves that we can even store previous values.

    Looking to level up your coding skills? Join our Python training program and unlock endless possibilities in the world of programming. Start your journey today and become a Python pro! 

    Conclusion

    React useEffect hook is a great tool to communicate directly with the DOM elements if we want to add special features to our app that we don’t want to get affected by the re-renders. 

    We can also use it to store previous values and access them whenever we need them as they are not affected by the re-renders and the value we stored in them remains unchanged. But it is only to be used when there is no other option and the other hooks like useState, useReducer, etc. are not working or not giving the proper result that we wish to have. 

    This was all about React and its useRef Hook, but React is just a powerful JS Library that allows us to do things like these. If you are interested in learning more about web development, try our web development certification course

    Frequently Asked Questions (FAQs)

    1Why is ref used in React?

     Ref is used in React to directly access the DOM node and React Element and if we want to change the value of the child component without using props. 

    2What is the difference between useRef and createRef?

    The main difference between them is that useRef uses the same ref throughout the function, persisting its value across re-renders while createRef creates a new ref every time and doesn’t store its value after every re-render. 

    3Is useRef Asynchronous?

    No, the reference update is synchronous, while the state update is asynchronous. 

    4Can we pass refs as props?

    There is an opt-in feature in React called forwardRef that lets some components take a ref they receive and pass it down (in other words, “forward” it) to a child.

    Profile

    Ateev Duggal

    Blog Author

    "I am Ateev Duggal, a front-end web developer, and a blogger. I write blogs mainly on React JS and have an experience of over 1.5 years of freelancing. I have worked on both static and dynamic projects again using React JS like a table to show clients data which was fetched using API, a review slider, pagination component, etc, and many websites like Parent, landing pages for Ataota, and many more.
    Some of my blogs have been published on freecodecamp, dev.to, Medium, Hashnode, and many other blogging platforms and developer's communities.
    My Primary skills not only include React JS but HTML5, CSS3, JS, Jquery, Git, and Bootstrap also. You can visit my GitHub Profile and LinkedIn profile for more information about me or you can visit my Website at tekolio.com".

    Share This Article
    Ready to Master the Skills that Drive Your Career?

    Avail your free 1:1 mentorship session.

    Select
    Your Message (Optional)

    Upcoming Web Development Batches & Dates

    NameDateFeeKnow more
    Course advisor icon
    Course Advisor
    Whatsapp/Chat icon