Skip to content

Commit 92c9780

Browse files
authored
Merge pull request Expensify#76216 from software-mansion-labs/war-in/remove-modal-dependency-from-ActiveHoverable
refactor: remove MODAL dependency from ActiveHoverable - limit rerenders
2 parents 075bb2e + bb3a3bf commit 92c9780

File tree

4 files changed

+14
-11
lines changed

4 files changed

+14
-11
lines changed

src/components/Hoverable/ActiveHoverable.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
/* eslint-disable react-compiler/react-compiler */
22
import {cloneElement, useCallback, useEffect, useMemo, useRef, useState} from 'react';
33
import {DeviceEventEmitter} from 'react-native';
4-
import useOnyx from '@hooks/useOnyx';
5-
import usePrevious from '@hooks/usePrevious';
64
import mergeRefs from '@libs/mergeRefs';
75
import {getReturnValue} from '@libs/ValueUtils';
86
import CONST from '@src/CONST';
9-
import ONYXKEYS from '@src/ONYXKEYS';
107
import type HoverableProps from './types';
118

129
type ActiveHoverableProps = Omit<HoverableProps, 'disabled'>;
@@ -15,7 +12,7 @@ type MouseEvents = 'onMouseEnter' | 'onMouseLeave' | 'onMouseMove';
1512

1613
type OnMouseEvents = Record<MouseEvents, (e: React.MouseEvent) => void>;
1714

18-
function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, shouldFreezeCapture, children, ref}: ActiveHoverableProps) {
15+
function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, isFocused = true, shouldFreezeCapture, children, ref}: ActiveHoverableProps) {
1916
const [isHovered, setIsHovered] = useState(false);
2017
const elementRef = useRef<HTMLElement | null>(null);
2118
const isScrollingRef = useRef(false);
@@ -81,16 +78,12 @@ function ActiveHoverable({onHoverIn, onHoverOut, shouldHandleScroll, shouldFreez
8178
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
8279
}, []);
8380

84-
const [modal] = useOnyx(ONYXKEYS.MODAL, {canBeMissing: true});
85-
const isModalVisible = modal?.isVisible;
86-
const prevIsModalVisible = usePrevious(isModalVisible);
87-
8881
useEffect(() => {
89-
if (!isModalVisible || prevIsModalVisible) {
82+
if (isFocused) {
9083
return;
9184
}
9285
setIsHovered(false);
93-
}, [isModalVisible, prevIsModalVisible]);
86+
}, [isFocused]);
9487

9588
const handleMouseEvents = useCallback(
9689
(type: 'enter' | 'leave') => () => {

src/components/Hoverable/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ type HoverableProps = {
1414
/** Whether to disable the hover action */
1515
isDisabled?: boolean;
1616

17+
/** Whether the screen containing the element is focused */
18+
isFocused?: boolean;
19+
1720
/** Function that executes when the mouse moves over the children. */
1821
onHoverIn?: () => void;
1922

src/components/MenuItem.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,9 @@ type MenuItemBaseProps = {
390390

391391
/** Whether the menu item contains nested submenu items. */
392392
hasSubMenuItems?: boolean;
393+
394+
/** Whether the screen containing the item is focused */
395+
isFocused?: boolean;
393396
};
394397

395398
type MenuItemProps = (IconProps | AvatarProps | NoIcon) & MenuItemBaseProps;
@@ -516,6 +519,7 @@ function MenuItem({
516519
copyable = false,
517520
hasSubMenuItems = false,
518521
ref,
522+
isFocused,
519523
}: MenuItemProps) {
520524
const theme = useTheme();
521525
const styles = useThemeStyles();
@@ -683,7 +687,7 @@ function MenuItem({
683687
shouldHideOnScroll={shouldHideOnScroll}
684688
>
685689
<View>
686-
<Hoverable>
690+
<Hoverable isFocused={isFocused}>
687691
{(isHovered) => (
688692
<PressableWithSecondaryInteraction
689693
onPress={shouldCheckActionAllowedOnPress ? callFunctionIfActionIsAllowed(onPressAction, isAnonymousAction) : onPressAction}

src/components/MenuItemList.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {useIsFocused} from '@react-navigation/native';
12
import React, {useRef} from 'react';
23
import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native';
34
import useSingleExecution from '@hooks/useSingleExecution';
@@ -55,6 +56,7 @@ type MenuItemListProps = {
5556
function MenuItemList({menuItems = [], shouldUseSingleExecution = false, wrapperStyle = {}, icon = undefined, iconWidth = undefined, iconHeight = undefined}: MenuItemListProps) {
5657
const popoverAnchor = useRef<View>(null);
5758
const {isExecuting, singleExecution} = useSingleExecution();
59+
const isFocused = useIsFocused();
5860

5961
/**
6062
* Handle the secondary interaction for a menu item.
@@ -106,6 +108,7 @@ function MenuItemList({menuItems = [], shouldUseSingleExecution = false, wrapper
106108
{...menuItemProps}
107109
disabled={!!menuItemProps.disabled || isExecuting}
108110
onPress={shouldUseSingleExecution ? singleExecution(menuItemProps.onPress) : menuItemProps.onPress}
111+
isFocused={isFocused}
109112
/>
110113
</OfflineWithFeedback>
111114
))

0 commit comments

Comments
 (0)