Last active
July 23, 2019 23:19
-
-
Save gragland/7556098f208ffd233b0a906cbc569110 to your computer and use it in GitHub Desktop.
React Hook recipe from https://usehooks.com. Demo: https://codesandbox.io/s/6jlvz1j5q3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.