What is the current behavior?
When using the Transition component with unmountOnExit, the exit animation works correctly, but the enter animation doesn't work. However, when I remove unmountOnExit, the enter animation works.
What is the expected behavior?
When using the Transition component with unmountOnExit, I expect the enter animation to work correctly.
Could you provide a CodeSandbox demo reproducing the bug?
https://codesandbox.io/s/admiring-fog-lhroc?file=/FadeScaleAlert.js
Is there anyone who knows why this bug is happening?
This is a very simple example of using the Transition component with unmountOnExit, but for some reason unmountOnExit caused the enter animation not to work.
Thanks for your time in advance!
Is there anyone who knows why this bug is happening?
This is a very simple example of using the
Transitioncomponent withunmountOnExit, but for some reasonunmountOnExitcaused the enter animation not to work.Thanks for your time in advance!
Is there anyone who knows why this bug is happening?
This is a very simple example of using the
Transitioncomponent withunmountOnExit, but for some reasonunmountOnExitcaused the enter animation not to work.Thanks for your time in advance!
May I ask if you have solved it
@parrot-designa no, I haven't solved it.
@parrot-designa no, I haven't solved it.
Do you have a social media account so we can talk to each other
@anatolzak Thank you for reporting this. I'll look into this.
@anatolzak Thank you for reporting this. I'll look into this.
Can it be fixed quickly? I don't remember this problem before
@anatolzak I've modified your CodeSandbox to work as expected. Is this your expected behavior?
https://codesandbox.io/s/still-thunder-82qud?file=/FadeScaleAlert.js
@koba04 that solution could work, but there is a 300ms delay between pressing the button and the scale animation starting visually.
The enter animation should happen between the exited state and entering state, since the exited state is the first state that occurs when the component mounts.
Making the enter animation happen between the entering and entered state causes a delay of 300ms between when the user presses the button to open the alert and when the user actually starts seeing the alert fading, which is terrible user experience in my opinion.
@koba04 thanks so much for working on this! I really appreciate your time and effort!
I had the same issue. I can suggest a workaround for this by dropping my code here. Pay attention to the setTimeout in the useEffect.
import {
Transition as RTGTransition,
TransitionGroup,
} from "react-transition-group";
const Animate = forwardRef(
(
{
children,
style,
defaultStyle,
transitionStyle,
transitionStatus,
className,
}: any,
outsideRef
) => {
const s = useMemo(
() => ({
...style,
...defaultStyle,
//@ts-ignore
...transitionStyle[transitionStatus],
}),
[transitionStatus, defaultStyle, transitionStyle]
);
return (
<div
ref={(node) => {
if (node) {
if (outsideRef) {
if (typeof outsideRef === "function") {
outsideRef(node);
} else {
outsideRef.current = node;
}
}
}
}}
className={className}
style={s}
>
{transitionStatus}
{children}
</div>
);
}
);
const Transition = forwardRef(
(
{
children,
defaultStyle,
transitionStyle,
className,
style,
...props
}: any,
outsideRef: any
) => {
const [_in, _setIn] = useState(false);
const timeoutRef = useRef<any>();
useEffect(() => {
// THIS IS THE IMPORTANT PART
requestAnimationFrame(() => {
timeoutRef.current = setTimeout(() => {
_setIn(props.in);
}, 5);
})
return () => {
clearTimeout(timeoutRef.current);
};
}, [props.in, timeoutRef]);
return (
<RTGTransition {...props} in={_in}>
{(transitionStatus) => {
return (
<Animate
ref={(node) => {
// ref.current = node;
if (outsideRef) {
if (typeof outsideRef === "function") {
outsideRef(node);
} else {
outsideRef.current = node;
}
}
}}
defaultStyle={defaultStyle}
style={style}
transitionStatus={transitionStatus}
transitionStyle={transitionStyle}
>
{children}
</Animate>
);
}}
</RTGTransition>
);
}
);
const ScaleUpTransition = ({
children,
delay = 0,
ease = "ease",
from,
to,
style,
timeout,
...props
}: any) => {
return (
<Transition
{...props}
timeout={timeout}
style={style}
defaultStyle={{
transformOrigin: "center",
willChange: "transform",
transform: `scale(${from})`,
transition: `transform ${timeout}ms ${ease} ${delay}ms`,
}}
transitionStyle={{
entering: {
transform: `scale(${to})`,
},
entered: {
transform: `scale(${to})`,
},
exiting: {
transform: `scale(${from})`,
},
exited: {
transform: `scale(${from})`,
},
}}
className={"ScaleUpTransition"}
>
{children}
</Transition>
);
};
const App = () => {
const [animate, setAnimate] = useState(false);
return (
<div>
<TransitionGroup>
{animate ? (
<ScaleUpTransition
in
timeout={2000}
from={1}
to={2}
appear
// mountOnEnter
// unmountOnExit
>
some
</ScaleUpTransition>
) : null}
</TransitionGroup>
<button
onClick={() => {
setAnimate(true);
}}
>
click
</button>
</div>
);
};
This is basically what #749 does.
Most helpful comment
The enter animation should happen between the
exitedstate andenteringstate, since theexitedstate is the first state that occurs when the component mounts.Making the enter animation happen between the
enteringandenteredstate causes a delay of 300ms between when the user presses the button to open the alert and when the user actually starts seeing the alert fading, which is terrible user experience in my opinion.