- React, TypeScript, Framer-motion
- DEMO ๋ฐ๋ก๊ฐ๊ธฐ
layoutId
๋ฅผ ์ด์ฉํ์ฌ Box์ Modal์ ์์ฐ์ค๋ฝ๊ฒ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค.whileHover
๋ฅผ ํตํด hover ์ ์คํ์ผ์ ์ง์ ํ ์ ์์ต๋๋ค.
<Box
onClick={() => setBoxId("first")}
layoutId={"first"}
whileHover={{
scale: 1.1,
transition: { duration: 0.3 },
}}
ref={boxRef}
>
Hover me! <br /> Click me!
</Box>
{boxId && (
<Overlay
onClick={() => setBoxId(null)}
initial={{ backgroundColor: "rgba(0,0,0,0)" }}
animate={{ backgroundColor: "rgba(0,0,0,0.5)" }}
exit={{ backgroundColor: "rgba(0,0,0,0)" }}
>
<Modal layoutId={boxId} $boxWidth={getBoxWidth()!}>
Thank you ๐ฅฐ
</Modal>
</Overlay>
)}
- useRef๋ฅผ ํตํด ์ป์ Box์ offsetWidth ๊ฐ์ styled-components์ props๋ก ์ ๋ฌํ์ฌ ์ฐฝ ํฌ๊ธฐ์ ๋ฐ๋ผ ๋ชจ๋ฌ์ width๋ฅผ ์ค์ ํฉ๋๋ค.
Full Screen | Responsive |
---|---|
const boxRef = useRef < HTMLDivElement > null;
const getBoxWidth = () => {
if (boxRef.current) {
return boxRef.current.offsetWidth;
}
};
const Modal = styled(motion.div)<{ $boxWidth: number }>`
width: ${({ $boxWidth }) => $boxWidth + "px"};
// ...
`;
layoutId
๋ฅผ ์ด์ฉํ์ฌ Circle์ ์์ฐ์ค๋ฝ๊ฒ switch ํ ์ ์์ต๋๋ค.
const [circleSwitched, setCircleSwitched] = useState(false);
const switchCircle = () => setCircleSwitched((prev) => !prev);
<Box>{!circleSwitched && <Circle layoutId="switch" />}</Box>
<Box>{circleSwitched && <Circle layoutId="switch" />}</Box>
- framer-motion์
useAnimation
ํ ๊ณผ react-intersection-observer์useInView
ํ ์ ์ฌ์ฉํ์ฌ ์คํฌ๋กค ์FadeIn
๋๋ ์ ๋๋ฉ์ด์ ๊ตฌํํ์์ต๋๋ค.
// ์ปค์คํ
ํ
const useScrollAnimation = () => {
const animation = useAnimation();
const { ref, inView } = useInView();
useEffect(() => {
if (inView) {
// ์๋ฆฌ๋จผํธ๊ฐ ๋ทฐํฌํธ ๋ด์ ๋ค์ด์ค๋ฉด visible ์ ๋๋ฉ์ด์
์คํ
animation.start("visible");
} else {
// ์๋ฆฌ๋จผํธ๊ฐ ๋ทฐํฌํธ์์ ๋ฒ์ด๋๋ฉด hidden ์ ๋๋ฉ์ด์
์คํ
animation.start("hidden");
}
}, [animation, inView]);
return { ref, animation };
};
// ์ปค์คํ
ํ
์ด ์ ์ฉ๋ Wrapper ์ปดํฌ๋ํธ
const ScrollWrapper = ({ children }: ScrollWrapperProps) => {
const { ref, animation } = useScrollAnimation();
return (
<motion.div
ref={ref}
variants={fadeInVariants}
initial="hidden"
animate={animation}
>
{children}
</motion.div>
);
};
// ์ ๋๋ฉ์ด์
์ ์ฉ
<ScrollWrapper>
<ExampleComponent />
</ScrollWrapper>;