React refs
For a new personal project I needed to use a React ref in order to obtain some information from the DOM. I have never needed to use them before and this is what I learned.
What was I trying to do?
I am working on an “art canvas” app, where I have a div in the middle of the screen that shows a shape in place of my cursor.
It is basically a web browser version of Microsoft Paint and is totally unnecessary, but it is a fun way for me to practice front-end skills and hopefully learn D3.js.
Anyway, I needed a way to calculate the distance between the viewport and the edges of my “canvas”, so I could render my shape wherever the cursor was hovering on the canvas div.
In vanilla JavaScript I can get the canvas div by using document.querySelector() or other similar document methods. Using element.getBoundingClientRect() will then give you information about the canvas div including its position within the viewport.
const element = document.querySelector("#main-canvas");
const rect = element.getBoundingClientRect();
Once I have the x and y values, I can subtract them from my mouse position values, and have my shape appear in the correct place on the screen.
However with React, in order to access DOM nodes in this way, I needed to use refs.
What are refs?
Note: these days I use React Hooks, which enable me to use function components instead of class components. I’ll explain refs in the context of function components.
As mentioned above, one of the biggest use cases for refs is when you want to access something in the DOM. Refs are similar to state in that their value can persist across component re-renders. The difference, though, is that a change in the value of your ref does not cause the component to re-render, whereas for state it does.
First, you create a variable with the useRef hook:
const inputRef = useRef();
Then you add the ref attribute to the component you are targeting.
<MainCanvas ref={inputRef} onMouseMove={handleMouseMove}></MainCanvas>
This gets our MainCanvas element and saves it to our ref variable above. inputRef is a JavaScript object, and we access our element using the “current” property. As you can see below, I can perform DOM related functions on the element, like getBoundingClientRect(), which gives me the x and y values I need.
const handleMouseMove = (event) => {
const {clientX, clientY} = event;
const displacementX = inputRef.current.getBoundingClientRect().x;
const displacementY = inputRef.current.getBoundingClientRect().y;
updateMousePositionX(clientX - displacementX);
updateMousePositionY(clientY - displacementY);
};
Conclusion
There is, of course, a lot more information out there on refs and how they can be used.
I recommend checking out the React hooks docs as well as this youtube video for more detailed information, as it was very helpful for me.