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.
Answer from Easwar on Stack OverflowThe 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.
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.
useState vs useRef
Can someone please explain the difference between useState and useReducer hook like I'm 5?
Videos
I haven't watched the video, but if the author suggests to use useRef() instead of state to save performance, he doesn't seem to have much clue of how React actually works.
React only applies changes to the DOM when it spots the changes in the virtual DOM, which is the representation of the nodes used to keep track of necessary changes. If your state change causes many DOM updates, it means that you do it wrong, most likely recreate a state value unnecessarily. The easiest way to this mistake is to recreate object in state, instead of memoizing it.
Using states means achieving much cleaner and reusable React code. Use useRef() only when you need to perform an action on a DOM element (like focus()) or when you need a value that needs to be accessed in the same cycle and/or is not rendered.
We have had issues with performance on large forms (forms with lots of inputs) and using state. While a simple state update is not much of a performance hit, if there are fields that update depending on that state, there may be a large performance hit, as there was in our case.
Our solution was to move to react hook form. While this may not answer your question directly, this is the direction we ended up going to solve issues that using state on the form caused and not to go down the slightly messy useRef path.
You also get some great methods like isDirty and isValid to help in form submission. You can also clear the form relatively easy with the reset method.