Skip to content

Instantly share code, notes, and snippets.

@SrJSDev
Last active February 26, 2024 16:38
Show Gist options
  • Save SrJSDev/16935299d98c1d298b1a539265a3052d to your computer and use it in GitHub Desktop.
Save SrJSDev/16935299d98c1d298b1a539265a3052d to your computer and use it in GitHub Desktop.
Swapper (ReactJS)
/******* Swapper styles *******/
.fade-out {
animation: fade-out-kf 0.5s forwards ease-out;
}
.fade-in {
animation: fade-out-kf 0.5s reverse ease-out;
}
@keyframes fade-out-kf {
0%,
33% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.slideX-out {
animation: slideX-out-kf 0.5s forwards ease-out;
}
.slideX-in {
animation: slideX-out-kf 0.5s reverse ease-out;
}
@keyframes slideX-out-kf {
0%,
33% {
transform: translateX(0);
}
100% {
transform: translateX(80vw);
}
}
import React, { useLayoutEffect, useState } from 'react';
type SwapperProps = {
children: React.ReactNode;
tick?: any;
cssEffect: {
out: {
className: string;
timerMs: number;
onStart?: () => void;
onEnd?: () => void;
};
into: {
className: string;
timerMs: number;
onStart?: () => void;
onEnd?: () => void;
};
};
};
export default function SwapperComponent({
children,
tick,
cssEffect = {
out: { className: 'slideX-out', timerMs: 500 }, // TODO: remove example
into: { className: 'fade-in', timerMs: 500 }, // TODO: remove example
},
}: SwapperProps) {
const { into, out } = cssEffect;
const [currChildren, setCurrChildren] = useState<React.ReactNode>(null);
const [isSwapping, setIsSwapping] = useState(false);
const effectTick = tick ?? children; // if children is memoized by parent, this is ok
useLayoutEffect(() => {
setIsSwapping(true);
out.Start?.();
const timeOutMs = !currChildren ? 0 : out.timerMs;
let timerId = setTimeout(() => {
setIsSwapping(false);
out.onEnd?.();
setCurrChildren(children);
into.onStart?.();
const timeIntoMs = into.timerMs;
timerId = setTimeout(() => into.onEnd?.(), timeIntoMs);
}, timeOutMs);
return () => {
clearTimeout(timerId);
};
}, [effectTick]);
if (!currChildren) return null;
return isSwapping ? (
<div key="out" className={out.className}>
{currChildren}
</div>
) : (
<div key="in" className={into.className}>
{children}
</div>
);
}
@SrJSDev
Copy link
Author

SrJSDev commented Feb 26, 2024

        <Swapper
          tick={pageState}
          cssEffect={{
            out: { className: 'slideX-out', timerMs: 500 },
            into: { className: 'fade-in', timerMs: 500 },
          }}
        >
          {pageState === PageState.QUESTION && <Question />}
          {pageState === PageState.EXPLANATION && <Explanation />}
        </Swapper>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment