Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import { useState, useRef } from 'react';
import { useSpring, animated } from 'react-spring';
// Displays a row of cards
// Usage of hook is within <Card> component below
function App() {
return (
<div className="container">
<div className="row">
{cards.map((card, i) => (
<div className="column">
<Card>
<div className="card-title">{card.title}</div>
<div className="card-body">{card.description}</div>
<img className="card-image" src={card.image} />
</Card>
</div>
))}
</div>
</div>
);
}
function Card({ children }) {
// We add this ref to card element and use in onMouseMove event ...
// ... to get element's offset and dimensions.
const ref = useRef();
// Keep track of whether card is hovered so we can increment ...
// ... zIndex to ensure it shows up above other cards when animation causes overlap.
const [isHovered, setHovered] = useState(false);
// The useSpring hook
const [animatedProps, setAnimatedProps] = useSpring(() => {
return {
// Array containing [rotateX, rotateY, and scale] values.
// We store under a single key (xys) instead of separate keys ...
// ... so that we can use animatedProps.xys.interpolate() to ...
// ... easily generate the css transform value below.
xys: [0, 0, 1],
// Setup physics
config: { mass: 10, tension: 400, friction: 40, precision: 0.00001 }
}
});
return (
<animated.div
ref={ref}
className="card"
onMouseEnter={() => setHovered(true)}
onMouseMove={({ clientX, clientY }) => {
// Get mouse x position within card
const x =
clientX -
(ref.current.offsetLeft -
(window.scrollX || window.pageXOffset || document.body.scrollLeft));
// Get mouse y position within card
const y =
clientY -
(ref.current.offsetTop -
(window.scrollY || window.pageYOffset || document.body.scrollTop));
// Set animated values based on mouse position and card dimensions
const dampen = 50; // Lower the number the less rotation
const xys = [
-(y - ref.current.clientHeight / 2) / dampen, // rotateX
(x - ref.current.clientWidth / 2) / dampen, // rotateY
1.07 // Scale
];
// Update values to animate to
setAnimatedProps({ xys: xys });
}}
onMouseLeave={() => {
setHovered(false);
// Set xys back to original
setAnimatedProps({ xys: [0, 0, 1] });
}}
style={{
// If hovered we want it to overlap other cards when it scales up
zIndex: isHovered ? 2 : 1,
// Interpolate function to handle css changes
transform: animatedProps.xys.interpolate(
(x, y, s) =>
`perspective(600px) rotateX(${x}deg) rotateY(${y}deg) scale(${s})`
)
}}
>
{children}
</animated.div>
);
}
@thebiltheory

This comment has been minimized.

Copy link

commented Jun 5, 2019

https://gist.github.com/gragland/7556098f208ffd233b0a906cbc569110#file-use-spring-example-jsx-L34
Creates an error as it doesn't return an interable.
Passing a function returning the object fixes the issue.

 const [animatedProps, setAnimatedProps] = useSpring(()=>{
    // Array containing [rotateX, rotateY, and scale] values.
    // We store under a single key (xys) instead of separate keys ...
    // ... so that we can use animatedProps.xys.interpolate() to ...
    // ... easily generate the css transform value below.
    xys: [0, 0, 1],
    // Setup physics
    config: { mass: 10, tension: 400, friction: 40, precision: 0.00001 }
  });```
@gragland

This comment has been minimized.

Copy link
Owner Author

commented Jul 23, 2019

@thebiltheory Thanks for pointing out this issue. Just updated the post with your fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.