1- import { CSSProperties , useCallback , useMemo , useReducer , useRef } from 'react' ;
1+ import { CSSProperties , useCallback , useEffect , useMemo , useReducer , useRef } from 'react' ;
22import { PlainObject } from '@gilbarbara/types' ;
33import { createPopper , Instance , ModifierArguments } from '@popperjs/core' ;
44import 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' ;
2424import getStyles from './modules/styles' ;
2525import { 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 ) {
0 commit comments