What is the React useRef() Hook and how does it work?
The useRef() Hook is a built-in React feature that creates a mutable object whose current property persists across component re-renders. Unlike state variables managed by useState, updating a ref does not trigger a re-render. This makes useRef() ideal for storing values that need to persist but do not directly affect the UI, such as DOM references, previous values, or timer IDs. Note: Overusing refs can make code harder to maintain and debug.
What are common use cases for useRef() in React applications?
Common use cases for useRef() include accessing DOM elements (e.g., focusing an input on mount), tracking previous values for comparison or undo functionality, managing timers and intervals, and building custom Hooks that need to persist values between renders. It is also used for caching computationally expensive results to optimize performance. Note: For UI state that should trigger re-renders, use useState instead.
What are the drawbacks or limitations of using useRef()?
Drawbacks of useRef() include manual management of updates (changes to .current do not trigger re-renders), potential for memory leaks if refs are not cleaned up, increased code complexity if overused, and debugging challenges since ref changes are not visible in React DevTools. It is also not suitable for managing UI state that should update the component. Note: For UI-driven state, prefer useState or useReducer.
How does useRef() differ from useState() in React?
useRef() creates a mutable object whose value persists across renders but does not trigger re-renders when updated. useState() creates state variables that, when updated, cause the component to re-render. useRef() is best for storing values that do not affect rendering, while useState() is for UI state. Note: Using useRef() for UI state can lead to bugs since the UI will not update automatically.
How does useRef() compare to createRef() in React?
useRef() is used in functional components and returns the same ref object on every render, maintaining its value throughout the component's lifecycle. createRef() is designed for class components and creates a new ref object on every render, which can lead to loss of previous values unless managed carefully. For modern React with Hooks, useRef() is recommended. Note: For legacy class components, createRef() is still required.
How can useRef() be used with content fetched from a CMS like Hygraph?
useRef() can store references to elements within dynamically fetched content from a CMS such as Hygraph. This enables features like lazy loading, smooth scrolling, or interactive components tied to specific content blocks. It can also cache results of complex queries to reduce load on the CMS and improve performance. Note: For managing content state that affects rendering, use useState() or context instead.
Hygraph Product Information & Features
What is Hygraph and what is its primary purpose?
Hygraph is a GraphQL-native Headless Content Management System (CMS) and Federation Platform designed to enable digital experiences at scale. It allows businesses to integrate multiple data sources and deliver content efficiently across channels, supporting modular and composable architectures. Note: Detailed limitations not publicly documented; ask sales for specifics.
What are the key features and capabilities of Hygraph?
Key features of Hygraph include: GraphQL-native architecture, content federation (integrating multiple data sources without duplication), enterprise-grade security and compliance (SOC 2 Type 2, ISO 27001, GDPR), Smart Edge Cache for performance, localization, granular permissions, and integrations with platforms like AWS S3, Netlify, Vercel, and BigCommerce. Note: Some advanced features may require higher-tier plans; see documentation for details.
What APIs does Hygraph offer?
Hygraph provides several APIs: a high-performance GraphQL Content API for querying and manipulating content, a Management API for handling project structure, an Asset Upload API for file management, and an MCP Server API for secure AI assistant communication. For details, see the API Reference documentation. Note: API rate limits and access may vary by plan.
What integrations are available with Hygraph?
Hygraph integrates with a variety of platforms, including Digital Asset Management (DAM) systems (Aprimo, AWS S3, Bynder, Cloudinary, Imgix, Mux, Scaleflex Filerobot), hosting and deployment platforms (Netlify, Vercel), Product Information Management (Akeneo), commerce solutions (BigCommerce), and translation/localization tools (EasyTranslate). For a full list, visit the Hygraph Marketplace. Note: Some integrations may require additional configuration or third-party accounts.
What technical documentation is available for Hygraph?
Hygraph provides extensive technical documentation, including API references, guides for schema components and references, onboarding tutorials, integration guides (e.g., Mux, Akeneo, Auth0), and AI feature documentation. Access these resources at hygraph.com/docs. Note: Documentation for legacy "Classic" projects is also available.
Security, Compliance & Performance
What security and compliance certifications does Hygraph have?
Hygraph is SOC 2 Type 2 compliant (since August 3, 2022), ISO 27001 certified for hosting infrastructure, and GDPR compliant. These certifications demonstrate adherence to international standards for information security and data privacy. Note: For more details, see the Secure Features page.
What security features does Hygraph offer?
Hygraph offers granular permissions, SSO integrations (OIDC/LDAP/SAML), audit logs, encryption in transit and at rest, regular backups with one-click recovery, secure API policies (custom origin, IP firewalls), and automatic SSL certificates for all endpoints. Note: Some features may be limited to enterprise plans.
How does Hygraph perform in terms of content delivery and API speed?
Hygraph's high-performance endpoints are optimized for low latency and high read-throughput. The read-only cache endpoint provides a 3-5x latency improvement for faster content delivery. Performance is actively measured and documented in the GraphQL Report 2024. Note: Actual performance may vary based on project complexity and geographic location.
Implementation, Use Cases & Customer Proof
How long does it take to implement Hygraph and how easy is it to start?
Implementation time varies by project. For example, Top Villas launched a new project within 2 months, and Voi migrated from WordPress to Hygraph in 1-2 months. Hygraph offers structured onboarding, starter projects, and extensive documentation to support both developers and non-technical users. Note: Complex migrations may require additional planning and resources.
Who is the target audience for Hygraph?
Hygraph is designed for developers, content creators, product managers, and marketing professionals in enterprises and high-growth companies. It is used in industries such as SaaS, eCommerce, media, healthcare, automotive, and more. Note: Some advanced features may be more relevant for enterprise or technical teams.
What business impact can customers expect from using Hygraph?
Customers have reported faster time-to-market (e.g., Komax achieved 3x faster launches), improved customer engagement (Samsung saw a 15% increase), cost reduction, and enhanced content consistency. AutoWeb increased website monetization by 20%, and Voi scaled multilingual content across 12 countries. Note: Results may vary based on implementation and use case.
What feedback have customers given about Hygraph's ease of use?
Customers praise Hygraph's intuitive interface, quick adaptability, and accessibility for non-technical users. For example, Sigurður G. (CTO) noted the UI is intuitive, and Charissa K. (Senior CMS Specialist) described it as fast to comprehend and localizable. Note: Some advanced configurations may require technical expertise.
What industries are represented in Hygraph's case studies?
Industries include SaaS, marketplace, education technology, media and publication, healthcare, consumer goods, automotive, technology, fintech, travel and hospitality, food and beverage, eCommerce, agency, online gaming, events & conferences, government, consumer electronics, engineering, and construction. See case studies for details. Note: Industry-specific features may vary.
Can you share specific customer success stories using Hygraph?
Yes. Samsung improved customer engagement by 15% with Hygraph. Komax achieved 3x faster time-to-market managing 20,000+ product variations. AutoWeb increased website monetization by 20%. Voi scaled multilingual content across 12 countries. See more at Hygraph's case studies page. Note: Outcomes depend on project scope and execution.
Pain Points & Problem Solving
What problems does Hygraph solve for its customers?
Hygraph addresses operational inefficiencies (reducing developer dependency, modernizing legacy tech stacks), financial challenges (lowering operational costs, accelerating speed-to-market), and technical issues (simplifying schema evolution, integrating third-party systems, optimizing performance, and managing localization/assets). Note: Some pain points may require custom solutions or advanced configuration.
Why should a customer choose Hygraph over other CMS platforms?
Hygraph is the first GraphQL-native Headless CMS, offers content federation, enterprise-grade security, and user-friendly tools for non-technical users. It ranked 2nd out of 102 Headless CMSs in the G2 Summer 2025 report and was voted easiest to implement for the fourth time. Case studies show proven ROI (e.g., Komax, Samsung). Note: Teams needing features not supported by GraphQL or requiring legacy CMS workflows may want to consider alternatives.
Learn how to use React's useRef Hook for DOM manipulation, performance optimization, and more in this in-depth guide.
Last updated by Motunrayo
on Jan 21, 2026
Originally written by Motunrayo
The useRef Hook is a versatile tool, often overlooked but crucial for managing references, optimizing performance, and interacting directly with the Document Object Model (DOM). While it might not be as widely discussed as useState or useEffect, it plays a pivotal role in many React applications.
This guide will discuss the useRef Hook, its use cases, practical applications, and drawbacks. By the end, you'll be well equipped to leverage its full potential, unlocking new levels of efficiency and control in your React projects.
The useRef() Hook is a built-in React feature that persists values between component re-renders. Unlike state variables managed by useState, values stored in a ref object remain unchanged across renders, making it ideal for scenarios where data doesn't directly affect the UI but is essential for the component's behavior.
When React encounters a useRef() Hook, it returns a plain JavaScript object with a single property: current. This current property stores mutable values, which can be of any type, from simple values like numbers and strings to complex objects, functions, or even references to DOM elements.
React assigns the initial value you define to the current property of the returned reference. React will set the value of the useRef to undefined if you don't provide an initial value. Importantly, you can update this current value directly without triggering a re-render of the component. This can be seen in the snippet below:
import{ useRef }from"react";
functionMyComponent(){
const reference =useRef(true);
console.log(reference.current);// true
}
Also, the returned reference object is mutable. You can update the current value directly, as shown in the snippet below.
Beyond its ability to persist values, the useRef() Hook has several vital roles in React applications:
Accessing DOM elements
Imagine a login page where users need to enter their username and password. To enhance the user experience, you can automatically direct their focus to the username field as soon as the page loads.
To achieve this, use the useRef 's capacity to access rendered DOM elements. This feature returns the referenced DOM element and its properties, providing room for direct manipulations.
import{ useRef, useEffect }from “react”
functionLogin(){
const usernameRef =useRef(null)
useEffect(()=>{
usernameRef.current.focus()
},[])
return(
<>
<form>
<input type="text" ref={usernameRef}/>
</form>
</>
)
}
The above snippet shows a Login component that renders a form with an input field for the user’s username. Also, it defines a username reference with the useRef Hook, which the focus() method is called on. This is executed inside a useEffect Hook, so it runs immediately after the UI finishes loading.
Tracking previous values
By storing the previous value of the input element as a state variable in a ref, you can monitor changes and address them accordingly. This technique is useful for implementing "undo" functionality, creating custom Hooks that need to compare previous and current values, or optimizing performance by preventing unnecessary calculations.
import{ useState, useRef, useEffect }from'react';
functionCounter(){
const[count, setCount]=useState(0);
const previousCountRef =useRef(count);// Store previous count in a ref
In this example, the useRef Hook stores the previous value of the count state variable. Every time the count changes, the useEffect Hook compares the new count to the value stored in the previousCountRef and logs a message to the console if they differ. This way, you can track how the count value evolves over time.
Managing timers and intervals
The useRef simplifies the management of timers and intervals within your components. You can store the timer's ID in a ref, allowing you to start, stop, or reset it as needed without triggering unnecessary re-renders.
import{ useState, useRef, useEffect }from'react';
functionmyTimer(){
const[seconds, setSeconds]=useState(0);
const timerRef =useRef(null);// Ref to store the timer ID
conststartTimer=()=>{
timerRef.current=setInterval(()=>{
setSeconds((prevSeconds)=> prevSeconds +1);
},1000);// Update every second
};
conststopTimer=()=>{
clearInterval(timerRef.current);
};
constresetTimer=()=>{
clearInterval(timerRef.current);
setSeconds(0);
};
// Cleanup function to clear the interval when the component unmounts
useEffect(()=>{
return()=>clearInterval(timerRef.current);
},[]);
return(
<div>
<p>Time elapsed:{seconds} seconds</p>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
<button onClick={resetTimer}>Reset</button>
</div>
);
}
In this example, a timer component was created using the useState and useRef Hooks. The useState Hook manages the seconds variable, which keeps track of the elapsed time. Meanwhile, useRef stores a reference to the interval ID (timerRef), which is responsible for updating the seconds every 1000 milliseconds (1 second).
The functions startTimer, stopTimer, and resetTimer control the timer's behavior. startTimer starts the interval, stopTimer stops it, and resetTimer resets the elapsed time to zero.
Building custom Hooks
When creating custom Hooks that need to maintain an internal state between renders, useRef becomes an invaluable asset. It enables you to store and update data privately within the Hook, promoting reusability and encapsulation of complex logic.
Imagine having multiple components that are required to maintain their previous state. It will appear too tedious to write this logic individually for every component. To avoid this, create a custom Hook using the useRef Hook as follows:
First, create a Hooks folder and a file usePreviousState.js, then add the following snippet:
import{ useRef, useEffect }from"react";
exportdefaultfunctionusePreviousState(value){
const ref =useRef();
useEffect(()=>{
ref.current= value;
});
return ref.current;
}
In the snippet above, a useRef instance was created, then on every page re-render, assign the value passed to the usePreviousState Hook to the ref.current. Finally, return the value of the ref.current.
To illustrate the custom Hook's utility, let’s revisit the 'tracking previous values' scenario
In the snippet above, all instances of the initial useRef were replaced with the newly created custom Hook. This shows that creating a custom Hook makes it possible to reuse complex logic.
Beyond its DOM manipulation capabilities, useRef shines as a performance enhancer. Imagine you have a computationally intensive task within your component, such as filtering a dataset or performing calculations, re-executing these operations on every render would be wasteful.
Storing values of these calculations within a ref variable using useRef can avoid unnecessary re-computations. Since refs persist across renders without triggering updates, the calculated value remains accessible and doesn't need to be recalculated unless the underlying data changes. Let's look at the example shown below:
import{ useState, useRef, useMemo }from"react";
exportdefaultfunctioncalculationComponent(){
const[inputNumber, setInputNumber]=useState(10);// Initial Calculation number
const calculateResult =useRef(null);// Ref to store the calculated result
constcalculateFib=(n)=>{
if(n <=1)return n;
returncalculateFib(n -1)+calculateFib(n -2);
};
// Memoize the calculation using useMemo
const memoizedCal =useMemo(()=>{
if(
calculateResult.current&&
calculateResult.current.input=== inputNumber
){
// If the input hasn't changed, reuse the cached result
return calculateResult.current.result;
}else{
// Calculate the result and store it in the ref
const result =calculateFib(inputNumber);
calculateResult.current={input: inputNumber, result };
In the snippet above, the useRef Hook, named calculateResult, is employed to optimize performance by caching the results of a computationally expensive calculation like the Fibonacci sequence. The calculateResult.current property stores both the input number and the calculated result, allowing for comparison on subsequent renders.
The useMemo Hook is used to memoize the calculation. It checks if the input number (inputNumber) has changed since the last render. If not, it returns the cached result from calculateResult.current, avoiding redundant computation. If the input number changes, the Fibonacci calculation is performed, and the result is stored in calculateResult.current for future reuse.
This memoization strategy improves the component's performance by preventing recalculations whenever the component re-renders due to unrelated state changes. While useRef offers performance benefits, knowing its potential drawbacks is essential.
Manual management: Unlike state variables managed with useState or useReducer, changes to the .current property of a ref attribute do not automatically trigger re-renders of your component. This means you need to manage updates and trigger re-renders manually when necessary and can add extra complexity to your code.
Potential memory leaks: If you're not careful, you can create dangling refs. This happens when a ref is still holding onto a reference to a DOM element or other object that has already been unmounted or removed from the DOM, leading to memory leaks.
Overuse: While refs are helpful in certain scenarios, overusing them can lead to a more complex and less maintainable codebase.
Debugging challenges: Since changes to refs don't trigger re-renders, debugging issues related to refs can sometimes be more complicated than debugging state-related problems.
Not suitable for array or object updates: Although you can store arrays or objects in a ref, updating individual properties or elements within them won't trigger re-renders. You'll need to manually update the entire array or object and trigger a re-render if you want those changes to be reflected in the UI. This can require more work than using state for mutable value structures.
To mitigate these drawbacks
Use the useRef when necessary and prioritize managing UI-related data with state (useState or useReducer) as it automatically triggers re-renders.
Always ensure proper cleanup of refs when components are removed from the DOM to prevent memory leaks.
Leverage debugging tools like React DevTools to track ref values and their impact if your code becomes overly reliant on refs.
Consider alternative approaches like lifting the state up or using context to streamline state management and component communication.
While both useRef and useState store values in React components, they serve different purposes and behave differently. Let's look at these Hooks, exploring their characteristics and how they contribute to state management in a React component.
Feature
useRef
useState
Mutable
Yes, the .current property can be changed directly
No, state updates must be done through the setter function (e.g., setCount)
Persistencea**crossr**enders
Yes, the value persists for the lifetime of the component
No, the value is reset on each re-render
Triggersr**e-render**
No, updating the .current property does not cause a re-render
Yes, updating state using the setter function triggers a re-render of the component
Commonu**sec**ases
Accessing DOM elements, storing previous values, managing timers/intervals, storing references
Managing UI state, storing data that directly affects the component's rendering
Before the Hooks era, React used createRef() for refs in their application. Let's break down their key distinctions when it comes to managing refs in React applications:
Feature
useRef Hook
createRef Function
Componentt**ype**
Exclusively used in functional components (introduced in React 16.8)
Designed for class components (pre-Hooks era)
Initialv**alue**
Takes an optional initial value, assigned to ref.current (defaults to undefined)
No initial value, ref.current is initially null
Re-renders
Returns the same ref object on each re-render, maintaining its value
Creates a new ref object on every re-render, losing the previous value
Persistence
Value persists for the entire component lifecycle
Value is lost on re-renders unless explicitly stored in a class component's instance variable
Flexibility
More flexible in functional components due to its persistence
Less flexible, requires additional state management for persistence in class components
If you're using functional components with React Hooks, useRef is the way to go. But if you're working with legacy class components, createRef is your best option.
However, consider refactoring to functional components and the useRef Hook for a more modern and maintainable approach. Next, let's discuss the useRef Hook in data fetched from content management systems.
useRef Hook in dynamic content fetched from CMSs
The useRef Hook, although not inherently tied to Content Management Systems (CMS), plays a crucial role in enhancing user interactions with dynamically fetched content from platforms like Hygraph, a GraphQL-Native Headless Content Management, and Federation System.
By storing references to specific elements within the fetched data, such as images or content blocks, developers can implement features like lazy loading, smooth scrolling, or interactive components.
Furthermore, useRef is valuable in optimizing data fetching from CMSs by caching results, especially for complex queries or large datasets. This caching mechanism reduces the load on the CMS and improves the application's performance as it avoids redundant data fetching operations.
While often overlooked, the useRef Hook is a powerful asset in a React developer's toolkit. It excels in managing references, optimizing performance, and enabling seamless interactions with DOM elements.
Understanding its capabilities and appropriate use cases allows developers to create more efficient, maintainable, and interactive React applications. Whether you're building complex animations, managing timers, or integrating with headless CMS platforms like Hygraph to optimize content delivery, useRef proves its value repeatedly.
Ready to explore the power of Hygraph? Sign up for a free-forever developer account and experience the seamless integration of Hygraph with React and its powerful Hook like useRef.
Blog Author
Motunrayo Moronfolu
Technical writer
Motunrayo Moronfolu is a Senior Frontend Engineer and Technical writer passionate about building and writing about great user experiences.
Share with others
Sign up for our newsletter!
Be the first to know about releases and industry news and insights.
Learn how to use React's useRef Hook for DOM manipulation, performance optimization, and more in this in-depth guide.
Last updated by Motunrayo
on Jan 21, 2026
Originally written by Motunrayo
The useRef Hook is a versatile tool, often overlooked but crucial for managing references, optimizing performance, and interacting directly with the Document Object Model (DOM). While it might not be as widely discussed as useState or useEffect, it plays a pivotal role in many React applications.
This guide will discuss the useRef Hook, its use cases, practical applications, and drawbacks. By the end, you'll be well equipped to leverage its full potential, unlocking new levels of efficiency and control in your React projects.
The useRef() Hook is a built-in React feature that persists values between component re-renders. Unlike state variables managed by useState, values stored in a ref object remain unchanged across renders, making it ideal for scenarios where data doesn't directly affect the UI but is essential for the component's behavior.
When React encounters a useRef() Hook, it returns a plain JavaScript object with a single property: current. This current property stores mutable values, which can be of any type, from simple values like numbers and strings to complex objects, functions, or even references to DOM elements.
React assigns the initial value you define to the current property of the returned reference. React will set the value of the useRef to undefined if you don't provide an initial value. Importantly, you can update this current value directly without triggering a re-render of the component. This can be seen in the snippet below:
import{ useRef }from"react";
functionMyComponent(){
const reference =useRef(true);
console.log(reference.current);// true
}
Also, the returned reference object is mutable. You can update the current value directly, as shown in the snippet below.
Beyond its ability to persist values, the useRef() Hook has several vital roles in React applications:
Accessing DOM elements
Imagine a login page where users need to enter their username and password. To enhance the user experience, you can automatically direct their focus to the username field as soon as the page loads.
To achieve this, use the useRef 's capacity to access rendered DOM elements. This feature returns the referenced DOM element and its properties, providing room for direct manipulations.
import{ useRef, useEffect }from “react”
functionLogin(){
const usernameRef =useRef(null)
useEffect(()=>{
usernameRef.current.focus()
},[])
return(
<>
<form>
<input type="text" ref={usernameRef}/>
</form>
</>
)
}
The above snippet shows a Login component that renders a form with an input field for the user’s username. Also, it defines a username reference with the useRef Hook, which the focus() method is called on. This is executed inside a useEffect Hook, so it runs immediately after the UI finishes loading.
Tracking previous values
By storing the previous value of the input element as a state variable in a ref, you can monitor changes and address them accordingly. This technique is useful for implementing "undo" functionality, creating custom Hooks that need to compare previous and current values, or optimizing performance by preventing unnecessary calculations.
import{ useState, useRef, useEffect }from'react';
functionCounter(){
const[count, setCount]=useState(0);
const previousCountRef =useRef(count);// Store previous count in a ref
In this example, the useRef Hook stores the previous value of the count state variable. Every time the count changes, the useEffect Hook compares the new count to the value stored in the previousCountRef and logs a message to the console if they differ. This way, you can track how the count value evolves over time.
Managing timers and intervals
The useRef simplifies the management of timers and intervals within your components. You can store the timer's ID in a ref, allowing you to start, stop, or reset it as needed without triggering unnecessary re-renders.
import{ useState, useRef, useEffect }from'react';
functionmyTimer(){
const[seconds, setSeconds]=useState(0);
const timerRef =useRef(null);// Ref to store the timer ID
conststartTimer=()=>{
timerRef.current=setInterval(()=>{
setSeconds((prevSeconds)=> prevSeconds +1);
},1000);// Update every second
};
conststopTimer=()=>{
clearInterval(timerRef.current);
};
constresetTimer=()=>{
clearInterval(timerRef.current);
setSeconds(0);
};
// Cleanup function to clear the interval when the component unmounts
useEffect(()=>{
return()=>clearInterval(timerRef.current);
},[]);
return(
<div>
<p>Time elapsed:{seconds} seconds</p>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
<button onClick={resetTimer}>Reset</button>
</div>
);
}
In this example, a timer component was created using the useState and useRef Hooks. The useState Hook manages the seconds variable, which keeps track of the elapsed time. Meanwhile, useRef stores a reference to the interval ID (timerRef), which is responsible for updating the seconds every 1000 milliseconds (1 second).
The functions startTimer, stopTimer, and resetTimer control the timer's behavior. startTimer starts the interval, stopTimer stops it, and resetTimer resets the elapsed time to zero.
Building custom Hooks
When creating custom Hooks that need to maintain an internal state between renders, useRef becomes an invaluable asset. It enables you to store and update data privately within the Hook, promoting reusability and encapsulation of complex logic.
Imagine having multiple components that are required to maintain their previous state. It will appear too tedious to write this logic individually for every component. To avoid this, create a custom Hook using the useRef Hook as follows:
First, create a Hooks folder and a file usePreviousState.js, then add the following snippet:
import{ useRef, useEffect }from"react";
exportdefaultfunctionusePreviousState(value){
const ref =useRef();
useEffect(()=>{
ref.current= value;
});
return ref.current;
}
In the snippet above, a useRef instance was created, then on every page re-render, assign the value passed to the usePreviousState Hook to the ref.current. Finally, return the value of the ref.current.
To illustrate the custom Hook's utility, let’s revisit the 'tracking previous values' scenario
In the snippet above, all instances of the initial useRef were replaced with the newly created custom Hook. This shows that creating a custom Hook makes it possible to reuse complex logic.
Beyond its DOM manipulation capabilities, useRef shines as a performance enhancer. Imagine you have a computationally intensive task within your component, such as filtering a dataset or performing calculations, re-executing these operations on every render would be wasteful.
Storing values of these calculations within a ref variable using useRef can avoid unnecessary re-computations. Since refs persist across renders without triggering updates, the calculated value remains accessible and doesn't need to be recalculated unless the underlying data changes. Let's look at the example shown below:
import{ useState, useRef, useMemo }from"react";
exportdefaultfunctioncalculationComponent(){
const[inputNumber, setInputNumber]=useState(10);// Initial Calculation number
const calculateResult =useRef(null);// Ref to store the calculated result
constcalculateFib=(n)=>{
if(n <=1)return n;
returncalculateFib(n -1)+calculateFib(n -2);
};
// Memoize the calculation using useMemo
const memoizedCal =useMemo(()=>{
if(
calculateResult.current&&
calculateResult.current.input=== inputNumber
){
// If the input hasn't changed, reuse the cached result
return calculateResult.current.result;
}else{
// Calculate the result and store it in the ref
const result =calculateFib(inputNumber);
calculateResult.current={input: inputNumber, result };
In the snippet above, the useRef Hook, named calculateResult, is employed to optimize performance by caching the results of a computationally expensive calculation like the Fibonacci sequence. The calculateResult.current property stores both the input number and the calculated result, allowing for comparison on subsequent renders.
The useMemo Hook is used to memoize the calculation. It checks if the input number (inputNumber) has changed since the last render. If not, it returns the cached result from calculateResult.current, avoiding redundant computation. If the input number changes, the Fibonacci calculation is performed, and the result is stored in calculateResult.current for future reuse.
This memoization strategy improves the component's performance by preventing recalculations whenever the component re-renders due to unrelated state changes. While useRef offers performance benefits, knowing its potential drawbacks is essential.
Manual management: Unlike state variables managed with useState or useReducer, changes to the .current property of a ref attribute do not automatically trigger re-renders of your component. This means you need to manage updates and trigger re-renders manually when necessary and can add extra complexity to your code.
Potential memory leaks: If you're not careful, you can create dangling refs. This happens when a ref is still holding onto a reference to a DOM element or other object that has already been unmounted or removed from the DOM, leading to memory leaks.
Overuse: While refs are helpful in certain scenarios, overusing them can lead to a more complex and less maintainable codebase.
Debugging challenges: Since changes to refs don't trigger re-renders, debugging issues related to refs can sometimes be more complicated than debugging state-related problems.
Not suitable for array or object updates: Although you can store arrays or objects in a ref, updating individual properties or elements within them won't trigger re-renders. You'll need to manually update the entire array or object and trigger a re-render if you want those changes to be reflected in the UI. This can require more work than using state for mutable value structures.
To mitigate these drawbacks
Use the useRef when necessary and prioritize managing UI-related data with state (useState or useReducer) as it automatically triggers re-renders.
Always ensure proper cleanup of refs when components are removed from the DOM to prevent memory leaks.
Leverage debugging tools like React DevTools to track ref values and their impact if your code becomes overly reliant on refs.
Consider alternative approaches like lifting the state up or using context to streamline state management and component communication.
While both useRef and useState store values in React components, they serve different purposes and behave differently. Let's look at these Hooks, exploring their characteristics and how they contribute to state management in a React component.
Feature
useRef
useState
Mutable
Yes, the .current property can be changed directly
No, state updates must be done through the setter function (e.g., setCount)
Persistencea**crossr**enders
Yes, the value persists for the lifetime of the component
No, the value is reset on each re-render
Triggersr**e-render**
No, updating the .current property does not cause a re-render
Yes, updating state using the setter function triggers a re-render of the component
Commonu**sec**ases
Accessing DOM elements, storing previous values, managing timers/intervals, storing references
Managing UI state, storing data that directly affects the component's rendering
Before the Hooks era, React used createRef() for refs in their application. Let's break down their key distinctions when it comes to managing refs in React applications:
Feature
useRef Hook
createRef Function
Componentt**ype**
Exclusively used in functional components (introduced in React 16.8)
Designed for class components (pre-Hooks era)
Initialv**alue**
Takes an optional initial value, assigned to ref.current (defaults to undefined)
No initial value, ref.current is initially null
Re-renders
Returns the same ref object on each re-render, maintaining its value
Creates a new ref object on every re-render, losing the previous value
Persistence
Value persists for the entire component lifecycle
Value is lost on re-renders unless explicitly stored in a class component's instance variable
Flexibility
More flexible in functional components due to its persistence
Less flexible, requires additional state management for persistence in class components
If you're using functional components with React Hooks, useRef is the way to go. But if you're working with legacy class components, createRef is your best option.
However, consider refactoring to functional components and the useRef Hook for a more modern and maintainable approach. Next, let's discuss the useRef Hook in data fetched from content management systems.
useRef Hook in dynamic content fetched from CMSs
The useRef Hook, although not inherently tied to Content Management Systems (CMS), plays a crucial role in enhancing user interactions with dynamically fetched content from platforms like Hygraph, a GraphQL-Native Headless Content Management, and Federation System.
By storing references to specific elements within the fetched data, such as images or content blocks, developers can implement features like lazy loading, smooth scrolling, or interactive components.
Furthermore, useRef is valuable in optimizing data fetching from CMSs by caching results, especially for complex queries or large datasets. This caching mechanism reduces the load on the CMS and improves the application's performance as it avoids redundant data fetching operations.
While often overlooked, the useRef Hook is a powerful asset in a React developer's toolkit. It excels in managing references, optimizing performance, and enabling seamless interactions with DOM elements.
Understanding its capabilities and appropriate use cases allows developers to create more efficient, maintainable, and interactive React applications. Whether you're building complex animations, managing timers, or integrating with headless CMS platforms like Hygraph to optimize content delivery, useRef proves its value repeatedly.
Ready to explore the power of Hygraph? Sign up for a free-forever developer account and experience the seamless integration of Hygraph with React and its powerful Hook like useRef.
Blog Author
Motunrayo Moronfolu
Technical writer
Motunrayo Moronfolu is a Senior Frontend Engineer and Technical writer passionate about building and writing about great user experiences.
Share with others
Sign up for our newsletter!
Be the first to know about releases and industry news and insights.