Understanding `useRef` vs. `createRef` in React: A Guide for Functional and Class Components
In React, both useRef
and createRef
are used to create references to DOM elements or store values that persist across re-renders of a component. However, they have distinct functionalities based on the type of component (functional or class-based) you're working with:
useRef
(Functional Components)
- Introduced in React 16.8,
useRef
is a hook specifically designed for functional components. - It creates a mutable ref object that holds a current value.
- The ref object persists across re-renders of the functional component, ensuring that the value doesn't get reset with each render.
- Syntax:
import React, { useRef } from 'react';
function MyComponent() {
const myRef = useRef(null); // Initial value can be anything
// ... rest of your component logic
return (
<div ref={myRef}>
{/* Your content */}
</div>
);
}
- Accessing the Ref Value: You can access the current value of the ref object using the
.current
property:
function focusInput() {
if (myRef.current) {
myRef.current.focus();
}
}
createRef
(Class Components)
createRef
is a React API (not a hook) that predates functional components.- It creates a ref object that's typically assigned to an instance property on a class component.
- However,
createRef
itself doesn't persist the ref value across re-renders. You need to store it in the component's instance for persistence.
import React from 'react';
class MyComponent extends React.Component {
constructor() {
super();
this.myRef = React.createRef();
}
// ... rest of your component methods
render() {
return (
<div ref={this.myRef}>
{/* Your content */}
</div>
);
}
}
- Accessing the Ref Value: Since
this.myRef
is stored on the component instance, you can access its value usingthis.myRef.current
throughout the class methods:
componentDidMount() {
if (this.myRef.current) {
this.myRef.current.focus();
}
}
Key Differences:
Feature | useRef (Functional) | createRef (Class) |
---|---|---|
Component Type | Functional | Class-based |
Persistence | Persists across re-renders | Requires manual storage |
Creation | Hook | API function |
Access | ref.current | this.ref.current |
When to Use Which:
- In modern React development, it's generally recommended to use
useRef
for both functional and class components (if you still need to maintain class components). createRef
is considered a legacy API primarily used in older codebases that rely on class components.
Additional Considerations:
- While
useRef
can store any value, it's often used for DOM references or to hold values that need to remain consistent across re-renders (e.g., timers, animation states). - Avoid using
useRef
for managing component state. State management is better handled with theuseState
hook.
import React, { useRef } from 'react';
function InputFocus() {
const inputRef = useRef(null);
function handleFocus() {
if (inputRef.current) {
inputRef.current.focus();
}
}
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
In this example:
- We create a functional component
InputFocus
. - Inside, we use the
useRef
hook to create a ref objectinputRef
with an initial value ofnull
. - We define a function
handleFocus
that checks if theinputRef.current
is not null (meaning the DOM element exists) and then callsfocus()
on it. - The JSX returns a
div
containing an input element with the ref assigned asinputRef
. - A button triggers the
handleFocus
function when clicked, focusing the input element.
Class Component (createRef
):
import React from 'react';
class Counter extends React.Component {
constructor() {
super();
this.count = 0;
this.countRef = React.createRef();
}
increment = () => {
this.count++;
this.countRef.current.textContent = this.count;
};
render() {
return (
<div>
<span ref={this.countRef}>0</span>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
- We create a class component
Counter
that extendsReact.Component
. - In the constructor, we initialize
this.count
to 0 and create a ref objectthis.countRef
usingReact.createRef()
. - We define an
increment
method that increases thecount
value and updates the content of the element referenced bythis.countRef
. - The JSX returns a
div
containing aspan
element with the ref assigned asthis.countRef
(initially displaying 0) and a button that triggers theincrement
method on click.
-
Controlled Components:
- This is a common pattern for managing form inputs. Instead of using a ref to access the DOM element's value, you store the input value in the component's state using
useState
. When the user interacts with the input, you update the state using anonChange
handler, keeping the component's state and DOM in sync.
import React, { useState } from 'react'; function InputValue() { const [inputValue, setInputValue] = useState(''); const handleChange = (event) => { setInputValue(event.target.value); }; return ( <div> <input type="text" value={inputValue} onChange={handleChange} /> <p>Current Value: {inputValue}</p> </div> ); }
- This is a common pattern for managing form inputs. Instead of using a ref to access the DOM element's value, you store the input value in the component's state using
-
- If you need to pass a function as a prop to a child component that needs to access or manipulate its own DOM element, you can use a callback function as a prop. The child component can then access the DOM element using its
ref
and call the callback function with the element as an argument.
Parent Component:
import React from 'react'; function ParentComponent() { const childRef = useRef(null); const handleFocus = () => { if (childRef.current) { childRef.current.focus(); } }; return ( <div> <ChildComponent ref={childRef} onFocus={handleFocus} /> <button onClick={handleFocus}>Focus Child Input</button> </div> ); }
Child Component:
import React from 'react'; function ChildComponent({ onFocus, ref }) { return ( <input type="text" ref={ref} /> ); }
- If you need to pass a function as a prop to a child component that needs to access or manipulate its own DOM element, you can use a callback function as a prop. The child component can then access the DOM element using its
-
State for Simple Values:
- If you only need to store a simple value that doesn't directly interact with the DOM and doesn't trigger re-renders when changed, you can simply use
useState
. This is suitable for values like timers, animation states, or temporary calculations.
import React, { useState, useEffect } from 'react'; function Timer() { const [seconds, setSeconds] = useState(0); useEffect(() => { const intervalId = setInterval(() => setSeconds(seconds + 1), 1000); return () => clearInterval(intervalId); // Cleanup on unmount }, []); return ( <div> <h1>Time elapsed: {seconds} seconds</h1> </div> ); }
- If you only need to store a simple value that doesn't directly interact with the DOM and doesn't trigger re-renders when changed, you can simply use
javascript reactjs react-hooks