Skip to content

Commit 0344099

Browse files
committed
fix: better handling of visibility prop changes
1 parent baf964f commit 0344099

File tree

3 files changed

+28
-20
lines changed

3 files changed

+28
-20
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-transitioning",
3-
"version": "1.0.6",
3+
"version": "1.0.7",
44
"description": "React components for easily implementing basic CSS animations and transitions",
55
"main": "dist/index.cjs.js",
66
"module": "dist/index.esm.js",

src/Transition.tsx

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,16 @@ export function Transition(props: TransitionProps) {
138138
addEndListener,
139139
} = props;
140140

141-
let ignoreInPropChange = false;
142-
143141
// Make phase state
144142
const [phase, setPhase] = useState(() => {
145-
ignoreInPropChange = true;
146-
if (!inProp) {
147-
return TransitionPhase.EXIT_DONE;
148-
}
149-
if (appear) {
150-
return TransitionPhase.APPEAR;
143+
switch (true) {
144+
case !inProp:
145+
return TransitionPhase.EXIT_DONE;
146+
case !!appear:
147+
return TransitionPhase.APPEAR;
148+
default:
149+
return TransitionPhase.APPEAR_DONE;
151150
}
152-
return TransitionPhase.APPEAR_DONE;
153151
});
154152

155153
// Effect for phase change
@@ -177,14 +175,18 @@ export function Transition(props: TransitionProps) {
177175
};
178176
}, [phase, duration]);
179177

180-
// Effect for initial phase
178+
// Effect for handling `in` prop changes
181179
useIsoEffect(() => {
182-
if (!ignoreInPropChange) {
183-
if (inProp) {
184-
setPhase(enter ? TransitionPhase.ENTER : TransitionPhase.ENTER_DONE);
185-
} else {
186-
setPhase(exit ? TransitionPhase.EXIT : TransitionPhase.EXIT_DONE);
187-
}
180+
const isExitPhase = [
181+
TransitionPhase.EXIT,
182+
TransitionPhase.EXIT_ACTIVE,
183+
TransitionPhase.EXIT_DONE,
184+
].includes(phase);
185+
if (inProp && isExitPhase) {
186+
setPhase(enter ? TransitionPhase.ENTER : TransitionPhase.ENTER_DONE);
187+
}
188+
if (!inProp && !isExitPhase) {
189+
setPhase(exit ? TransitionPhase.EXIT : TransitionPhase.EXIT_DONE);
188190
}
189191
}, [inProp]);
190192

src/TransitionGroup.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Children, cloneElement, useRef, isValidElement } from 'react';
2+
import { useIsoEffect } from './useIsoEffect';
23

34
export type TransitionGroupProps = {
45
children: React.ReactNode;
@@ -49,7 +50,7 @@ type VisibleElement = {
4950
export function TransitionGroup(props: TransitionGroupProps) {
5051
const { children, appear = false, enter = true, exit = false, duration = 500 } = props;
5152

52-
const firstRenderRef = useRef(true);
53+
const mountedRef = useRef(false);
5354
const prevVisibleElementsRef = useRef<VisibleElement[]>([]);
5455
const nextVisibleElements: VisibleElement[] = [];
5556
const nextElements: React.ReactElement[] = [];
@@ -71,9 +72,9 @@ export function TransitionGroup(props: TransitionGroupProps) {
7172
const elementClone = cloneElement(element, {
7273
in: !removeTimeout,
7374
enter: false,
74-
appear: firstRenderRef.current ? (element.props.appear ?? appear) : (element.props.enter ?? enter),
7575
exit: element.props.exit ?? exit,
7676
duration: element.props.duration ?? duration,
77+
appear: mountedRef.current ? (element.props.enter ?? enter) : (element.props.appear ?? appear),
7778
});
7879

7980
nextVisibleElements.push({ element, removeTimeout });
@@ -128,8 +129,13 @@ export function TransitionGroup(props: TransitionGroupProps) {
128129
addVisibleElement(derivedElements[i]);
129130
}
130131

132+
// Mark as mounted
133+
useIsoEffect(() => {
134+
mountedRef.current = true;
135+
}, []);
136+
131137
// Save the visible elements
132138
prevVisibleElementsRef.current = nextVisibleElements;
133-
firstRenderRef.current = false;
139+
134140
return nextElements;
135141
}

0 commit comments

Comments
 (0)