Reputation: 925
I've done some research on how to trigger CSS animation once the element comes into view, and I've found the answer that makes use of IntersectionObserver and element.classList.add('.some-class-name')
Above method is demonstrated in pure CSS, but I want to implement it with Material-UI. Here is my code.
import React, { useEffect } from 'react';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
root: {
height: '100vh'
},
box: {
opacity: 0,
width: 100,
height: 100,
backgroundColor: 'red'
},
animated: {
animationName: '$fadein',
animationDuration: '1s'
},
'@keyframes fadein': {
'0%': {
opacity: 0
},
'100%': {
opacity: 1
}
},
}));
function App() {
const classes = useStyles();
useEffect(() => {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0) {
// trigger animation
entry.target.classList.add('animated');
// remove observer
observer.unobserve(entry.target);
}
});
});
const element = document.getElementById('item');
observer.observe(element);
}, []);
return (
<div>
<div className={classes.root} />
<div id="item" className={classes.box} />
</div>
);
};
export default App;
Unfortunately, the above code isn't working and I think it's because the className 'animated' does not exist. I know Material-UI has internal logic that generates the unique className, so my question is how do I figure out the real className of 'animated'? Or, is there a better way to go about this? Any help would be appreciated.
Upvotes: 1
Views: 2995
Reputation: 925
This is what I came up with.
import React, { useEffect, useState, useRef } from 'react';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
root: {
height: '100vh'
},
box: {
opacity: 0,
width: 100,
height: 100,
backgroundColor: 'red'
},
animated: {
animationName: '$fadein',
animationDuration: '1s',
animationFillMode: 'forwards'
},
'@keyframes fadein': {
'0%': {
opacity: 0
},
'100%': {
opacity: 1
}
}
}));
function App() {
const classes = useStyles();
const BoxSection = (props) => {
const [isVisible, setVisible] = useState(false);
const domRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => setVisible(entry.isIntersecting));
});
observer.observe(domRef.current);
return () => observer.unobserve(domRef.current); // clean up
}, []);
return (
<div className={`${classes.box} ${isVisible ? classes.animated : ''}`} ref={domRef}>
{props.children}
</div>
);
};
return (
<div>
<div className={classes.root} />
<BoxSection />
</div>
);
}
export default App;
Basically, I've decided to use state to trigger animation by adding the class like above. I've got some pointers from this article, if anyone is interested.
Upvotes: 1