Lesson Description

The "Snap Effect on Hover" Lesson is part of the full, Award-Winning Marketing Websites course featured in this preview video. Here's what you'd learn in this lesson:

Matias adds a snap effect when the "Start" text is hovered. A state property is added to manage whether or not the mouse cursor div should snap to the center position. If the "Start" text is hovered, the div will use the same Lerp animation effect to resize and snap to the center position.

Preview

Transcript from the "Snap Effect on Hover" Lesson

[00:00:00]
>> Matias Gonzalez: OK, now, finally, what I want to do is to do the snap tricks. So when I hover over this element, I want this mouse to ignore my cursor and just snap to the center and scale to cover the element. So let's create two callbacks that we can add to this element. One would be on pointer enter and another would be on pointer out, so const on pointer enter.

[00:00:47]
Sorry, use callback. And the other one would be on pointer leave. So pointer leave. And I'm going to add that to my H1 right here, so on pointer enter. It's going to be this callback and on pointer leave. It's going to be this other callback. Now what I want to do is to switch some state when I enter and switch it back when I leave.

[00:01:25]
So let's actually useState for that. The reason again for using a state is that this is not really going to happen on every frame unless we move the mouse really, really fast. So it's OK to have some re-render here and there. Const, let's call it snap and set snap. I'm going to use a state.

[00:01:51]
And this state is going to hold an object. And I'm going to store an X and a Y axis. Actually, I'm going to initialize this state to 0, so. I'm going to use a state and I'm going to initialize this state as null because initially I don't want the snap to be triggered, but I'm going to add a type for this state so it can be either null or an object.

[00:02:30]
And on this object I'm going to store the X value, the x position. The Y position, the width, the height. And the height. Actually, this should be so when I hover this element, I want to set snap. Let's actually make it 0 to start and then y 0. And then the width, it's going to be some hard coded value.

[00:03:38]
Like that. So X, Y, width and height. And then if I leave, let's just reset to null, set snap to null. So again, what's happening here is, let's log the snap value. So this is going to be null. If I hover, I'm going to have my object. If I remove the mouse, it's going to be null again.

[00:04:17]
So let's actually get some concrete values in here. What I actually want to do is get the half of the window for the x axis, so window.innerWidth divided by 2. And for the y axis, let's get the window.innerHeight divided by 2. And then let's stay with the same value for the width and the height for now.

[00:04:53]
Let's actually make this cursor react to the snap variable, so when we are lerping. If our snap variable is defined, so if snap is defined. We're going to run some logic, otherwise, we're going to lerp into our mouse. So if the snap variable is defined instead of lerping into the mouse, what I want to do is to lerp into the snap variable, so snap.

[00:05:32]
The target is going to be snap.x. And here's going to be snap.y. And actually we need to add this since it's a state, let's add it as a dependency, so snap. So let's check if everything's working correctly and it is. OK, so as soon as I hover, we're going to run the callback, we're going to measure where that element is and we're going to set our follower element to be at the center of that element, at the center of the screen actually.

[00:06:10]
We could measure where the element is in order to like add some other places that we can follow to. Let's actually scale the rectangle to cover the area. So since we are using a state and causing a re-render, we can just go ahead and connect that variable into the style here, so I'm going to add style.

[00:06:52]
I'm going to set the width to be snap. If snap is defined. I'm going to set the width to snap.width. Otherwise, let's leave it as undefined. Let's do the same for the height. And let's type this correctly as React.CSSProperties. So what's going to happen is when this variable is defined, it's going to override whatever value I just put in here.

[00:07:33]
And since here I am using pixels, let's actually go ahead and add the pixels to it. So grabbing this number and just adding pixels to the end and transforming that into a string. So if I hover. I should see that, OK, we got the value but we were hard coding this value as 100% so we actually need to measure our elements.

[00:08:07]
So the way we can measure this element is we can actually access to it on this callback so I can see what the types of the pointer event is and it's actually a pointer event handler. So let's just type my callback like this. And import this type. So right now, I will have access to the event.

[00:08:48]
And as I can see the event has a target. Which is OK, which element caused this event to fire in this case this H1, so I can just measure the target so. Is it current target. The way I can measure the target is getting client rects. Getting client rects is going to return me an array of numbers.

[00:09:29]
Let's actually debug what's happening here so let's console out. Get client rects. So if I hover I'm going to see that I get an array of DOMRect lists. And this is basically an array of objects and it's going to contain a bunch of information about the elements so it's going to contain the right left top position, the width and the height for example which is what I am interested into right now.

[00:10:11]
So let's use this information to scale this square properly. So I can do const rect is equal to get client rects and let's access the first one. And then let's set the width to rect.width and the height to rect.height. So again, by accessing the event.currentTarget we can actually access what element triggered this callback and measure that element using getBoundingClientRect.

[00:10:59]
If I go ahead and hover, then I can, the element will scale properly and snap to the cursor. Maybe I can like add some padding to it to have like a little bit of extra space. And that way we can create like a cursor following effect with like a snap by combining like a couple of frame loops and some mouse callbacks.

[00:11:28]
Any questions related to this so far? Had a quick question on the like the useRef for the X and Y like object, is there a reason to use useRef over like an object literal or like a different React hook? Yes, if I were to use just like. And I'll check here like. Like this.

[00:11:53]
Every time I have a re-render on my page this object's going to get redefined. So I want to make sure that this object is the original one and I don't ever recreate that object again and the easiest way to do that is just to create a reference. So again, if I were to do this, let's manually create like a current.

[00:12:25]
And let's then do X. Let's actually do it with the position because it will be more obvious the issue. So I'm going to do const cursor position ref, and I'm going to manually create like a reference, so current. It's going to be X0 and Y0. So when I hover over my title, this is going to cause a re-render so this object is going to be created again.

[00:13:00]
It's not going to be, it's not going to store the older position, it's actually going to like reset everything. In fact, already the useEffect is asking me to add it as a dependency and if I do that, if I go to the example every time I hover it's going to like reset because I just created a new object on every re-render.

[00:13:28]
So I can see how it's like going all over the place. So by using a reference I'm just creating this object once and like storing it and then editing it in different places. This is especially useful for when working with 3D. Like, I want to create like something that is very, very expensive.

[00:13:50]
I just want to do that once. I don't want to like recreate things over and over on different renders. You can also use memo, but usually the linter is going to complain about that, so a reference can be easier.

Learn Straight from the Experts Who Shape the Modern Web

  • 250+
    In-depth Courses
  • Industry Leading Experts
  • 24
    Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now