Skip to content

Commit fb6d34a

Browse files
committed
Refactor event handling and lifecycle methods
1 parent 948a0c0 commit fb6d34a

File tree

2 files changed

+41
-43
lines changed

2 files changed

+41
-43
lines changed

src/index.tsx

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CSSProperties, useCallback, useMemo, useReducer, useRef } from 'react';
1+
import { CSSProperties, useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
22
import { PlainObject } from '@gilbarbara/types';
33
import { createPopper, Instance, ModifierArguments } from '@popperjs/core';
44
import is from 'is-lite';
@@ -20,7 +20,7 @@ import {
2020
once,
2121
randomId,
2222
} from './modules/helpers';
23-
import { useMount, useSingleton, useUnmount, useUpdateEffect } from './modules/hooks';
23+
import { useUpdateEffect } from './modules/hooks';
2424
import getStyles from './modules/styles';
2525
import { Props, State, Statuses, Styles } from './types';
2626

@@ -84,19 +84,16 @@ export default function ReactFloater(props: Props) {
8484
const { changed } = useTreeChanges(state);
8585
const { changed: changedProps } = useTreeChanges(props);
8686

87-
const updateState = useCallback(
88-
(nextState: Partial<State>, callback_?: () => void) => {
89-
if (isMounted.current) {
90-
setState(nextState);
91-
stateRef.current = { ...state, ...nextState };
87+
const updateState = useCallback((nextState: Partial<State>, callback_?: () => void) => {
88+
if (isMounted.current) {
89+
setState(nextState);
90+
stateRef.current = { ...stateRef.current, ...nextState };
9291

93-
if (callback_) {
94-
callback_();
95-
}
92+
if (callback_) {
93+
callback_();
9694
}
97-
},
98-
[setState, state],
99-
);
95+
}
96+
}, []);
10097

10198
const toggle = useCallback(
10299
(forceStatus?: Statuses) => {
@@ -354,17 +351,17 @@ export default function ReactFloater(props: Props) {
354351
wrapperOptions?.placement,
355352
]);
356353

357-
const handleLoad = useRef(() => {
354+
const handleLoad = useCallback(() => {
358355
if (popperRef.current) {
359356
popperRef.current.forceUpdate();
360357
}
361358

362359
if (wrapperPopper.current) {
363360
wrapperPopper.current.forceUpdate();
364361
}
365-
});
362+
}, []);
366363

367-
const handleTransitionEnd = useRef(() => {
364+
const handleTransitionEnd = useCallback(() => {
368365
if (wrapperPopper.current) {
369366
wrapperPopper.current.forceUpdate();
370367
}
@@ -379,7 +376,7 @@ export default function ReactFloater(props: Props) {
379376
}
380377
},
381378
);
382-
});
379+
}, [updateState, callback, props]);
383380

384381
const handleClick = useCallback(() => {
385382
if (is.boolean(open)) {
@@ -449,7 +446,7 @@ export default function ReactFloater(props: Props) {
449446
}
450447
}, [initPopper, positionWrapper]);
451448

452-
const cleanUp = () => {
449+
const cleanUp = useCallback(() => {
453450
if (popperRef.current) {
454451
popperRef.current.destroy();
455452
popperRef.current = undefined;
@@ -459,17 +456,23 @@ export default function ReactFloater(props: Props) {
459456
wrapperPopper.current.destroy();
460457
wrapperPopper.current = undefined;
461458
}
462-
};
459+
}, []);
463460

464-
useSingleton(() => {
461+
// Global load event listener (singleton)
462+
useEffect(() => {
465463
if (canUseDOM()) {
466-
window.addEventListener('load', handleLoad.current);
464+
window.addEventListener('load', handleLoad);
467465
}
468-
});
466+
}, [handleLoad]);
469467

470-
useMount(() => {
468+
// Mount effect
469+
useEffect(() => {
471470
isMounted.current = true;
471+
initPopper();
472+
}, [initPopper]);
472473

474+
// Debug logging effect
475+
useEffect(() => {
473476
log({
474477
title: 'init',
475478
data: {
@@ -482,16 +485,22 @@ export default function ReactFloater(props: Props) {
482485
},
483486
debug: currentDebug,
484487
});
488+
}, [children, target, open, positionWrapper, currentDebug]);
485489

486-
initPopper();
487-
});
488-
489-
useUnmount(() => {
490-
isMounted.current = false;
490+
// Unmount effect
491+
useEffect(() => {
492+
return () => {
493+
isMounted.current = false;
494+
clearTimeout(eventDelayTimer.current);
495+
cleanUp();
496+
window.removeEventListener('load', handleLoad);
497+
};
498+
}, [cleanUp, handleLoad]);
491499

492-
cleanUp();
493-
window.removeEventListener('load', handleLoad.current);
494-
});
500+
// Update state ref when state changes
501+
useEffect(() => {
502+
stateRef.current = state;
503+
}, [state]);
495504

496505
// handle changes
497506
useUpdateEffect(() => {
@@ -532,7 +541,7 @@ export default function ReactFloater(props: Props) {
532541
}
533542

534543
if (floaterRef.current && changed('status', [STATUS.RENDER, STATUS.CLOSING])) {
535-
once(floaterRef.current, 'transitionend', handleTransitionEnd.current);
544+
once(floaterRef.current, 'transitionend', handleTransitionEnd);
536545
}
537546

538547
if (changed('status', STATUS.IDLE, STATUS.CLOSING) && popperRef.current) {

src/modules/hooks.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,6 @@ export function useMount(effect: EffectCallback) {
99
useEffectOnce(effect);
1010
}
1111

12-
export function useSingleton(callback: () => void): void {
13-
const hasBeenCalled = useRef(false);
14-
15-
if (hasBeenCalled.current) {
16-
return;
17-
}
18-
19-
callback();
20-
hasBeenCalled.current = true;
21-
}
22-
2312
export function useUnmount(fn: () => any): void {
2413
const fnRef = useRef(fn);
2514

0 commit comments

Comments
 (0)