useRef and createRef are two ways to create references in React with different use cases:
// useRef in functional component
const inputRef = useRef(null);
// createRef in class component
this.inputRef = createRef();useRef and createRef are tools for working with DOM elements and storing mutable values in React! They solve similar tasks but work differently. 🔧
| Characteristic | useRef | createRef |
|---|---|---|
| Component type | Functional | Class |
| Lifetime | Persists between renders | Created anew each time |
| Performance | High | Lower |
| Modernity | Modern approach | Legacy approach |
useRef creates a mutable object that persists between renders:
import { useRef, useEffect } from 'react';
function MyComponent() {
const inputRef = useRef(null);
const countRef = useRef(0);
useEffect(() => {
// Focus on input
inputRef.current.focus();
}, []);
const handleClick = () => {
countRef.current += 1;
console.log(countRef.current); // Doesn't trigger rerender
};
return (
<div>
<input ref={inputRef} />
<button onClick={handleClick}>Increment counter</button>
</div>
);
}createRef creates a new reference object on each call:
import React, { Component, createRef } from 'react';
class MyComponent extends Component {
constructor(props) {
super(props);
this.inputRef = createRef();
this.countRef = createRef();
}
componentDidMount() {
// Focus on input
this.inputRef.current.focus();
}
handleClick = () => {
console.log(this.inputRef.current.value);
};
render() {
return (
<div>
<input ref={this.inputRef} />
<button onClick={this.handleClick}>Get value</button>
</div>
);
}
}function Component() {
const ref = useRef(null); // Created once
// ref.current is always the same object
console.log(ref); // { current: null }
return <div ref={ref} />;
}class Component extends React.Component {
render() {
const ref = createRef(); // Created on every render!
return <div ref={ref} />;
}
}
// Correct usage in class
class Component extends React.Component {
constructor(props) {
super(props);
this.ref = createRef(); // Created once
}
render() {
return <div ref={this.ref} />;
}
}// useRef
function ScrollToTop() {
const topRef = useRef(null);
const scrollToTop = () => {
topRef.current?.scrollIntoView({ behavior: 'smooth' });
};
return (
<div>
<div ref={topRef}>Top of page</div>
<button onClick={scrollToTop}>Go to top</button>
</div>
);
}
// createRef
class ScrollToTop extends Component {
constructor(props) {
super(props);
this.topRef = createRef();
}
scrollToTop = () => {
this.topRef.current?.scrollIntoView({ behavior: 'smooth' });
};
render() {
return (
<div>
<div ref={this.topRef}>Top of page</div>
<button onClick={this.scrollToTop}>Go to top</button>
</div>
);
}
}// useRef for storing values without rerender
function Timer() {
const [time, setTime] = useState(0);
const intervalRef = useRef(null);
const startTimer = () => {
intervalRef.current = setInterval(() => {
setTime(prev => prev + 1);
}, 1000);
};
const stopTimer = () => {
clearInterval(intervalRef.current);
};
return (
<div>
<p>Time: {time}</p>
<button onClick={startTimer}>Start</button>
<button onClick={stopTimer}>Stop</button>
</div>
);
}❌ Wrong:
// createRef in render - created anew!
class Component extends React.Component {
render() {
const ref = createRef();
return <div ref={ref} />;
}
}✅ Correct:
// createRef in constructor
class Component extends React.Component {
constructor(props) {
super(props);
this.ref = createRef();
}
render() {
return <div ref={this.ref} />;
}
}Main differences between useRef and createRef:
Use useRef in modern development! 🚀