React: useState or useRef?
useRef
is useful when you want to track value change, but don't want to trigger re-render or useEffect
by it.
Most use case is when you have a function that depends on value, but the value needs to be updated by the function result itself.
For example, let's assume you want to paginate some API result:
const [filter, setFilter] = useState({});
const [rows, setRows] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const fetchData = useCallback(async () => {
const nextPage = currentPage + 1;
const response = await fetchApi({...filter, page: nextPage});
setRows(response.data);
if (response.data.length) {
setCurrentPage(nextPage);
}
}, [filter, currentPage]);
fetchData
is using currentPage
state, but it needs to update currentPage
after successful response. This is inevitable process, but it is prone to cause infinite loop aka Maximum update depth exceeded error
in React. For example, if you want to fetch rows when component is loaded, you want to do something like this:
useEffect(() => {
fetchData();
}, [fetchData]);
This is buggy because we use state and update it in the same function.
We want to track currentPage
but don't want to trigger useCallback
or useEffect
by its change.
We can solve this problem easily with useRef
:
const currentPageRef = useRef(0);
const fetchData = useCallback(async () => {
const nextPage = currentPageRef.current + 1;
const response = await fetchApi({...filter, page: nextPage});
setRows(response.data);
if (response.data.length) {
currentPageRef.current = nextPage;
}
}, [filter]);
We can remove currentPage
dependency from useCallback
deps array with the help of useRef
, so our component is saved from infinite loop.
Basically, We use UseState in those cases, in which the value of state should be updated with re-rendering.
when you want your information persists for the lifetime of the component you will go with UseRef because it's just not for work with re-rendering.
The main difference between both is :
useState
causes re-render, useRef
does not.
The common between them is, both useState
and useRef
can remember their data after re-renders. So if your variable is something that decides a view layer render, go with useState
. Else use useRef
I would suggest reading this article.