What you'll learn:
useTransform with MotionValueuseSpringuseTransform to improve useMotionValueLet’s add some improvements to our code here.
Remember useTransform? We can use it to make our code a little bit tidier.
We’ll start by importing useTransform and creating a couple of MotionValues for our mouse position.
import "./styles.css"
function App() {
let mouseX = useMotionValue(0)
let mouseY = useMotionValue(0)
...
}
For birdX, instead of creating a MotionValue from scratch, we’ll create one that will change along with mouseX.
function App() {
let mouseX = useMotionValue(0)
let mouseY = useMotionValue(0)
let birdX = useTransform(mouseX, [], [])
let birdY = useTransform(mouseY, [], [])
...
}
For the following parameters, we need an input and output range such as the ranges we used in the Tinder Swipe example.
However, this time, let’s try something different. By looking at the useTransform documentation, we can see that there are only two parameters when calling useTransform in the example on the right. We know that there are only two parameters because there is only one comma.
The first parameter is the source MotionValue called parent in the documentation and the second parameter is something we'll learn about now!
;(value) => value * 2
What is this equal sign and greater-than symbol here?
It turns out that it’s just a function. That statement is equivalent to writing this.
function(value) {
return value * 2;
}
In context,
let birdX = useTransform(mouseX, (value) => value * 2)
vs
let birdX = useTransform(mouseX, function (value) {
return value * 2
})
The only difference is that one is shorter and looks nicer. I hope you know which one that is!
useTransform works with MotionValueLet’s look at how this version of useTransform works.
let birdX = useTransform(mouseX, function (value) {
return value * 2
})
First of all, useTransform will create a new MotionValue but not from scratch. It uses mouseX as a reference, takes out the value from mouseX, calls this anonymous function, and puts the return value into a new MotionValue. To illustrate, if mouseX is 100, birdX would be assigned a value of 200.
Furthermore, whenever the value of mouseX changes, the process I just listed would be repeated: the anonymous function is called with the new mouseX value and returns the new value into birdX.
In our case, we want the return value to be divided by 3.5 and not multiplied by 2.
let birdX = useTransform(mouseX, function (value) {
return value / 3.5
})
As you’ve just seen, we can convert the function to a shorter form in a few steps.
Removing function
let birdX = useTransform(mouseX, (value) => { return value / 3.5 })Because of this "=>" sign that looks like a fat >arrow, these kinds of functions are called arrow >functions.
Removing ()
When there’s only one parameter, we can ignore the >parentheses.
let birdX = useTransform(mouseX, (value) => { return value / 3.5 })
Removing {} and the return statement
When a function only has a
returnstatement, we >can remove the keywordreturnand the curly brackets.let birdX = useTransform(mouseX, (value) => value / 3.5)
Making the same changes to our other variables,
let birdX = useTransform(mouseX, value => value / 3.5)
let birdY = useTransform(mouseY, value => value / 3.5)
let cloudsX = useTransform(mouseX, value => value / 8)
let cloudsY = useTransform(mouseY, value => value / 8)
let sunX = useTransform(mouseX, value => value / 10)
let sunY = useTransform(mouseY, value => value / 10)
let bgX = useTransform(mouseX, value => value / 14)
let bgY = useTransform(mouseY, value => value / 14)
MotionValue animationNow, inside of onMouseMove, we can remove all our set functions and replace them with two lines!
<Frame
size={550}
background={null}
center
onMouseMove={function(event) {
let offsetX = event.clientX - window.innerWidth / 2
let offsetY = event.clientY - window.innerHeight / 2
mouseX.set(offsetX)
mouseY.set(offsetY)
}}
>
However, there’s one more issue. The movement of all these image layers now feels a bit stiff.
It no longer has that bouncy effect as our previous solution with useAnimation.
* Check it out yourself: Parallax Animation
This is because, unlike useAnimation, useMotionValue does not animate with a spring. However, the fix is really simple.
useSpringIf we check out the Framer documentation again, we can find something called useSpring.
Therefore, instead of importing and calling useMotionValue, we'll import and call useSpring.
import "./styles.css"
function App() {
let mouseX = useSpring(0)
let mouseY = useSpring(0)
...
}
We now have our spring animation back.
Now that we know how to use both useAnimation, useMotionValue and how to convert animation styles, we'll learn about the differences between the two in the next post while we improve our "Tinder" slider!.