When to use useRef over useState
Use useRef
to persist state between re-renders, but avoid re-renders when the state changes. Use useState
to persist state and re-render when the state changes.
More details
Most of the time you’re gonna use useState
because you’ll need the component to re-render in order to properly represent the state on the screen.
useRef
comes in handy when you need to persist a piece of state that you don’t usually show on the screen. Let's see some examples:
Reference a DOM node
Focus the input when the button is clicked. See it in action →
function App() {
const inputRef = React.useRef(null)
return (
<div className="App">
<h1>useRef - focus input</h1>
<input ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus</button>
</div>
)
}
Reference a timer
In this "count down" example, we keep a reference to the timer to clean it up when the count down finishes or when the component get's unmounted. See it in action →
// ...
function App() {
const [count, setCount] = React.useState(10)
const timerRef = React.useRef(null)
const clearTimer = () => {
window.clearTimeout(timerRef.current)
}
React.useEffect(() => {
let didCancel = false
timerRef.current = window.setInterval(() => {
if (!didCancel) {
setCount(c => {
if (c === 0) {
clearTimer()
return c
}
return c - 1
})
}
}, 1000)
// ...
}, [])
// ...
}
Cache API results
Custom React Hook that fetches data from a given URL and caches the results. See it in action →
// ...
const reducer = (state, { type, payload }) => { ... };
const initialState = { ... };
export default function useDogs(url) {
const [{ data, error, loading }, dispatch] = useReducer(
reducer,
initialState
);
const cache = useRef({});
useEffect(() => {
let didCancel = false;
if (cache.current[url]) {
dispatch({ type: FETCH_SUCCESS, payload: cache.current[url] });
return;
}
dispatch({ type: FETCH_REQUEST });
fetch(url)
.then(res => res.json())
.then(res => {
if (!didCancel) {
const payload = res.message;
cache.current[url] = payload;
dispatch({ type: FETCH_SUCCESS, payload });
}
})
.catch(err => {
if (!didCancel) {
dispatch({ type: FETCH_FAILURE, payload: err.message });
}
});
return () => {
didCancel = true;
};
}, [url, cache]);
return { data, error, loading };
}
Thanks for reading! Have something to say? Please, leave a comment!