Refs have been a handy way to reference DOM elements in Class Components, but did you know you can use refs for other things as well? In this lesson, we’ll examine how to leverage the useRef hook inside a Function Component. We’ll first use this ref to attach to a React element, which you may already be familiar with, but then we’ll examine how to use a ref to simulate a Class instance variable.
Thanks for the videos. If the todoId
can be kept track of using either useState
or useRef
, what are the pros and cons to each approach?
Alex, good question about where to keep todoId
. You could technically do either as you mentioned, but I lean toward keeping data that is needed for the render inside of useState
. In this case the todoId
isn't needed for the render, but is intended to keep track of the last ID so it can be incremented when a new item is added. Technically that variable could be stored anywhere (even global, but I prefer to limit global variables).
This course is wonderful! Putting everything on codesandbox helps tremendously. I was wondering what the reason was to have this line of code inputRef.current.focus(); line 30 of the focus example. Don't we get the same result if we just use line 31? inputRef.current.select();
Thanks Anthony
What is the advantage of useRef over something like this: let count = Number(window.localStorage.getItem('count') || 0)
let incCount =()=>{
window.localStorage.setItem('count', count + 1)
return count+1
}
.... // todoId.current
id: incCount() ,
text: newTodo,
completed: false
id: incCount() , text: newTodo, completed: false
Tony, good question. MDN notes that...
Calling element.select() will not necessarily focus the input, so it is often used with HTMLElement.focus().
https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/select
Tony, another good question. It'd be better if the UI didn't figure out the IDs in the first place, but since there is no server counterpart the UI is doing the logic. You could introduce another localStorage item that you always keep up to date with the largest ID known, however, if that number was based on count it could lead to bugs. Imagine you had 10 items and deleted 5 of them. If it was based on count, then the next item you create could reuse an existing ID (depending on what you deleted). So, that is why when the app loads I iterate through the todos and look for the Max ID and set that to the ref. You could also store that to localStorage, but you'd need to keep it up-to-date and make sure it kept track of the largest ID that exists. If you had TONS of data in localStorage then my solution may be slower on startup since I do a loop, but browsers are pretty fast so I don't think that's a worry.
why not just write let todoId = 0;
and then just change todoId++
value? =)
why not just write
let todoId = 0;
and then just changetodoId++
value? =)
Because the values of local variables inside the function are gone after each render. So according to your suggestion, todoId will always be zero. When putting the values in state of refs, the values it contains are persisted between renders.
why not just write let todoId = 0; and then just change todoId++ value? =)
Creating variable outside of the function can do the trick and retain value between rerenders but there is a small issue. Every instance of component in the application will share the same value.