Skip to content

Instantly share code, notes, and snippets.

@jameskerr
Created September 9, 2023 03:11
Show Gist options
  • Save jameskerr/bf93075667e6539ace88582c3b080d57 to your computer and use it in GitHub Desktop.
Save jameskerr/bf93075667e6539ace88582c3b080d57 to your computer and use it in GitHub Desktop.
React Debut: A component for animating elements in an out as they mount and unmount.
import {CSSTransition} from "react-transition-group"
import {forwardRef, useImperativeHandle, useRef, useState} from "react"
import {call} from "src/util/call"
export function useDebut(args: {enter?: () => any; exit: () => any}) {
const ref = useRef<any>()
const api = {
props: {
ref,
onExit: args.exit,
},
enter() {
ref.current?.setExiting(false)
call(args.enter)
},
exit() {
ref.current?.setExiting(true)
},
toggle() {
if (!ref.current) {
// Not mounted, so enter
call(args.enter)
} else if (ref.current.exiting) {
// Is exiting, so cancel exit
ref.current.setExiting(false)
} else {
// Is entered, so exit
ref.current.setExiting(true)
}
},
isExiting: ref.current?.exiting ?? false,
}
return api
}
export const Debut = forwardRef(function Debut(props: {onExit; children}, ref) {
const [exiting, setExiting] = useState(false)
useImperativeHandle(ref, () => ({exiting, setExiting}), [exiting, props])
return (
<CSSTransition
appear
in={!exiting}
// @ts-ignore
addEndListener={(node, done) =>
node.addEventListener("transitionend", done, false)
}
onExited={() => {
call(props.onExit)
setExiting(false)
}}
>
{props.children}
</CSSTransition>
)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment