I am using framer-motion to animate a change in grid columns.
Here is what I want to do:
(Basically, I want to do step 1 and 2 backwards after the user has switched back)
I've already achieved step 1 and 2. Here is the functional component:
const DrumButtons = (props) => {
const drumButtonsVariants = {
hidden: {
y: "140vh",
},
visible: {
y: 0,
transition: {
type: "tween",
duration: 1,
delay: 0.1,
},
},
exit: {
y: "140vh",
transition: {
type: "tween",
duration: 1,
delay: 0.1,
},
},
};
let dbWrapperStyle = {};
if (!props.minimized) {
dbWrapperStyle = {
gridTemplateColumns: "1fr 1fr 1fr 1fr",
};
}
let singleWrapperStyle = {
width: "100%",
height: "100%",
};
let buttonTransition = { duration: 0.5, delay: 0.1 };
return (
<div id="db-wrapper" style={dbWrapperStyle}>
<AnimatePresence>
{props.buttonsarr.map((elem, i) => {
return (
<motion.div
variants={drumButtonsVariants}
initial="hidden"
animate="visible"
exit="exit"
key={elem.press}
style={singleWrapperStyle}
>
<motion.button
layout
transition={buttonTransition}
key={elem.press}
className="drum-pad"
onClick={dbHandleClickWrapper(
props.changetext,
props.buttonsarr
)}
id={elem.name}
>
<span className="front">{elem.press.toUpperCase()}</span>
<audio
key={elem.press.toUpperCase()}
id={elem.press.toUpperCase()}
src={props.buttonsarr[i].source}
preload="auto"
className="clip"
></audio>
</motion.button>
</motion.div>
);
})}
</AnimatePresence>
</div>
);
};
What is the problem, exactly?
So here's what currently happens when switching back from "maximized" to "minimized":
Here is what I've tried:
when: "beforeChildren"
to the transitions of the drumButtonsVariants
. Nothing changed.You can view my full code here:
(main branch) https://github.com/Julian-Sz/FCC-Drum-Machine/tree/main
(version with the problem) https://github.com/Julian-Sz/FCC-Drum-Machine/tree/284606cac7cbc4bc6e13bf432c563eab4814d370
Feel free to copy and fork this repository!
The trick is to use State for the dbWrapperStyle
.
Then, AnimatePresence
with onExitComplete
can be used.
onExitComplete
fires: The grid columns change to 3 columns and the component gets rerendered. The removal from the DOM and the grid change are happening after each other (without any delay) - resulting in a smooth animation!const DrumButtons = (props) => {
const drumButtonsVariants = {
visible: {
y: 0,
transition: {
type: "tween",
duration: 0.8,
delay: 0.1,
},
},
exit: {
y: "140vh",
transition: {
type: "tween",
duration: 0.8,
delay: 0.1,
},
},
};
// BEFORE------------
// let dbWrapperStyle = {};
// if (!props.minimized) {
// dbWrapperStyle = {
// gridTemplateColumns: "1fr 1fr 1fr 1fr",
// };
// }
// AFTER-------------
const [dbWrapperStyle, setWrapperStyle] = useState({});
useEffect(() => {
if (!props.minimized) {
setWrapperStyle({ gridTemplateColumns: "1fr 1fr 1fr 1fr" });
}
}, [props.minimized]);
let singleWrapperStyle = {
width: "100%",
height: "100%",
};
let buttonTransition = {
type: "spring",
duration: 0.9,
delay: 0.1,
bounce: 0.5,
};
return (
<div id="db-wrapper" style={dbWrapperStyle}>
<AnimatePresence
onExitComplete={() => {
setWrapperStyle({ gridTemplateColumns: "1fr 1fr 1fr" });
}}
>
{props.buttonsarr.map((elem, i) => {
return (
<motion.div
variants={drumButtonsVariants}
initial="exit"
animate="visible"
exit="exit"
key={elem.press}
style={singleWrapperStyle}
>
<motion.button
layout
transition={buttonTransition}
key={elem.press}
className="drum-pad"
onClick={dbHandleClickWrapper(
props.changetext,
props.buttonsarr
)}
id={elem.name}
>
<span className="front">{elem.press.toUpperCase()}</span>
<audio
key={elem.press.toUpperCase()}
id={elem.press.toUpperCase()}
src={props.buttonsarr[i].source}
preload="auto"
className="clip"
></audio>
</motion.button>
</motion.div>
);
})}
</AnimatePresence>
</div>
);
};