Skip to content

Commit

Permalink
fix: listeners not removed
Browse files Browse the repository at this point in the history
  • Loading branch information
chrispader committed Dec 13, 2023
1 parent 0423495 commit f73d652
Showing 1 changed file with 46 additions and 33 deletions.
79 changes: 46 additions & 33 deletions src/components/CustomStatusBarAndBackground/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useContext, useEffect} from 'react';
import React, {useCallback, useContext, useEffect, useRef, useState} from 'react';
import useTheme from '@hooks/useTheme';
import {navigationRef} from '@libs/Navigation/Navigation';
import StatusBar from '@libs/StatusBar';
Expand All @@ -15,7 +15,7 @@ type CustomStatusBarAndBackgroundProps = {
function CustomStatusBarAndBackground({isNested = false}: CustomStatusBarAndBackgroundProps) {
const {isRootStatusBarDisabled, disableRootStatusBar} = useContext(CustomStatusBarAndBackgroundContext);
const theme = useTheme();
const [statusBarStyle, setStatusBarStyle] = React.useState(theme.statusBarStyle);
const [statusBarStyle, setStatusBarStyle] = useState(theme.statusBarStyle);

const isDisabled = !isNested && isRootStatusBarDisabled;

Expand All @@ -33,41 +33,54 @@ function CustomStatusBarAndBackground({isNested = false}: CustomStatusBarAndBack
};
}, [disableRootStatusBar, isNested]);

const updateStatusBarStyle = useCallback(() => {
if (isDisabled) {
return;
}
const listenerCount = useRef(0);
const updateStatusBarStyle = useCallback(
(listenerId?: number) => {
// Check if this function is either called through the current navigation listener or the general useEffect which listens for theme changes.
if (listenerId !== undefined && listenerId !== listenerCount.current) {
return;
}

// Set the status bar colour depending on the current route.
// If we don't have any colour defined for a route, fall back to
// appBG color.
let currentRoute: ReturnType<typeof navigationRef.getCurrentRoute> | undefined;
if (navigationRef.isReady()) {
currentRoute = navigationRef.getCurrentRoute();
}
// Set the status bar colour depending on the current route.
// If we don't have any colour defined for a route, fall back to
// appBG color.
let currentRoute: ReturnType<typeof navigationRef.getCurrentRoute> | undefined;
if (navigationRef.isReady()) {
currentRoute = navigationRef.getCurrentRoute();
}

let currentScreenBackgroundColor = theme.appBG;
let newStatusBarStyle = theme.statusBarStyle;
if (currentRoute && 'name' in currentRoute && currentRoute.name in theme.PAGE_THEMES) {
const screenTheme = theme.PAGE_THEMES[currentRoute.name];
currentScreenBackgroundColor = screenTheme.backgroundColor;
newStatusBarStyle = screenTheme.statusBarStyle;
}
let currentScreenBackgroundColor = theme.appBG;
let newStatusBarStyle = theme.statusBarStyle;
if (currentRoute && 'name' in currentRoute && currentRoute.name in theme.PAGE_THEMES) {
const screenTheme = theme.PAGE_THEMES[currentRoute.name];
currentScreenBackgroundColor = screenTheme.backgroundColor;
newStatusBarStyle = screenTheme.statusBarStyle;
}

// Don't update the status bar style if it's the same as the current one, to prevent flashing.
if (newStatusBarStyle === statusBarStyle) {
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor});
} else {
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor, statusBarStyle: newStatusBarStyle});
setStatusBarStyle(newStatusBarStyle);
}
}, [isDisabled, statusBarStyle, theme.PAGE_THEMES, theme.appBG, theme.statusBarStyle]);
// Don't update the status bar style if it's the same as the current one, to prevent flashing.
if (newStatusBarStyle === statusBarStyle) {
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor});
} else {
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor, statusBarStyle: newStatusBarStyle});
setStatusBarStyle(newStatusBarStyle);
}
},
[statusBarStyle, theme.PAGE_THEMES, theme.appBG, theme.statusBarStyle],
);

// Update the status bar style everytime the navigation state changes
// Add navigation state listeners to update the status bar every time the route changes
// We have to pass a count as the listener id, because "react-navigation" somehow doesn't remove listeners properyl
useEffect(() => {
navigationRef.addListener('state', updateStatusBarStyle);
return () => navigationRef.removeListener('state', updateStatusBarStyle);
}, [updateStatusBarStyle]);
if (isDisabled) {
return;
}

const listenerId = ++listenerCount.current;
const listener = () => updateStatusBarStyle(listenerId);

navigationRef.addListener('state', listener);
return () => navigationRef.removeListener('state', listener);
}, [isDisabled, theme.appBG, updateStatusBarStyle]);

// Update the status bar style everytime the theme changes
useEffect(() => {
Expand All @@ -76,7 +89,7 @@ function CustomStatusBarAndBackground({isNested = false}: CustomStatusBarAndBack
}

updateStatusBarStyle();
}, [isDisabled, theme.statusBarStyle, updateStatusBarStyle]);
}, [isDisabled, theme, updateStatusBarStyle]);

// Update the global background (on web) everytime the theme changes.
// The background of the html element needs to be updated, otherwise you will see a big contrast when resizing the window or when the keyboard is open on iOS web.
Expand Down

0 comments on commit f73d652

Please sign in to comment.