Reputation: 3777
Example is a functional component in which I am rendering a div
conditionally. I want this div
to fade-in when rendered conditionally and fade-out vice versa.
For that, I have maintained two local state variables: render
and fadeIn
which are computed based on show
prop passed down to the Example component.
What I've done is:
show
prop it true, I set render
as true, so the div
renders conditionally and after a timeout of 10ms
I set fadeIn
as true which will set CSS classname for my div as show
.show
prop it false, I set fadeIn
as false, which will set CSS classname for my div as hide
and after a timeout of 200ms
(transition time in CSS) I set render
as false so the div
is hidden conditionally.Code:
interface Props {
show: boolean;
}
const Example: React.FC<Props> = ({ show, }) => {
const [render, setRender] = useState(false);
const [fadeIn, setFadeIn] = useState(false);
useEffect(() => {
if (show) {
// render component conditionally
setRender(show);
// change state to for conditional CSS classname which will
// animate opacity, I had to give a timeout of 10ms else the
// component shows up abruptly
setTimeout(() => {
setFadeIn(show);
}, 10);
} else {
// change state to change component classname for opacity animation
setFadeIn(false);
// hide component conditionally after 200 ms
// because that's the transition time in CSS
setTimeout(() => {
setRender(false);
}, 200);
}
}, [
show,
]);
return (
<div>
{render && (
<div className={`container ${fadeIn ? 'show' : 'hide'}`} />
)}
</div>
);
};
Stylesheet:
.container {
width: 100px;
height: 100px;
background-color: black;
transition: opacity 0.2s ease;
}
.show {
opacity: 1;
}
.hide {
opacity: 0;
}
I believe this is not a good coding practice to achieve the functionality and should maintain only one local state in my component. I need your suggestions on how I can solve this in a better way without using any 3rd Party Library. Thanks :)
Upvotes: 23
Views: 25731
Reputation: 1005
Actually there is a HTML attribute for this situationes called onAnimationEnd
or onAnimationStart
based on your case.
Example:
export default function App() {
const [isMounted, setIsMounted] = useState(false);
const [showDiv, setShowDiv] = useState(false);
return (
<div className="App">
<button onClick={() => {
setIsMounted(!isMounted)
if (!showDiv) setShowDiv(true); //We should Render our Div
}
}>Show/Hide</button>
{ //Conditional Rendering
showDiv && <div
className="transitionDiv"
style={isMounted ? mountedStyle : unmountedStyle}
onAnimationEnd={() => { if (!isMounted) setShowDiv(false) }}
></div>}
</div>
);
}
More info can be found in this article
Upvotes: 5
Reputation: 2042
const [render, setRender] = useState(false);
useEffect(() => {
if(show) {
setTimeout(() => {
setRender(true);
}, 2000);
} else {
setRender(false);
}
}, [show]);
<div className={cs(s.render, render ? 'show' : undefined)}>
<p>{content}</p>
</div>
Css:
.render {
...,
visibility: hidden;
opacity: 0;
transition: all 0.6s ease;
}
.show {
visibility: visible;
opacity: 1;
}
Hope be helpful.
Upvotes: 4