Skip to content

Commit

Permalink
Merge pull request #28549 from software-mansion-labs/Sebryu-performan…
Browse files Browse the repository at this point in the history
…ce-context-optimization

Optimized context usages and set up eslint rule for optimization
  • Loading branch information
mountiny authored Oct 19, 2023
2 parents 550dbf5 + cc4052c commit 2b98d2b
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 132 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ module.exports = {
overrides: [
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
plugins: ['react'],
rules: {
'rulesdir/no-multiple-onyx-in-file': 'off',
'rulesdir/onyx-props-must-have-default': 'off',
'react-native-a11y/has-accessibility-hint': ['off'],
'react/jsx-no-constructed-context-values': 'error',
'react-native-a11y/has-valid-accessibility-descriptors': [
'error',
{
Expand Down
5 changes: 3 additions & 2 deletions src/components/AnimatedStep/AnimatedStepProvider.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useState} from 'react';
import React, {useMemo, useState} from 'react';
import PropTypes from 'prop-types';
import AnimatedStepContext from './AnimatedStepContext';
import CONST from '../../CONST';
Expand All @@ -9,8 +9,9 @@ const propTypes = {

function AnimatedStepProvider({children}) {
const [animationDirection, setAnimationDirection] = useState(CONST.ANIMATION_DIRECTION.IN);
const contextValue = useMemo(() => ({animationDirection, setAnimationDirection}), [animationDirection, setAnimationDirection]);

return <AnimatedStepContext.Provider value={{animationDirection, setAnimationDirection}}>{children}</AnimatedStepContext.Provider>;
return <AnimatedStepContext.Provider value={contextValue}>{children}</AnimatedStepContext.Provider>;
}

AnimatedStepProvider.propTypes = propTypes;
Expand Down
33 changes: 18 additions & 15 deletions src/components/Attachments/AttachmentCarousel/Pager/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable es/no-optional-chaining */
import React, {useRef, useState, useImperativeHandle} from 'react';
import React, {useRef, useState, useImperativeHandle, useMemo} from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import {GestureHandlerRootView, createNativeWrapper} from 'react-native-gesture-handler';
Expand Down Expand Up @@ -126,22 +126,25 @@ function AttachmentCarouselPager({
scrollEnabled: shouldPagerScroll.value,
}));

const contextValue = useMemo(
() => ({
canvasWidth: containerWidth,
canvasHeight: containerHeight,
isScrolling,
pagerRef,
shouldPagerScroll,
onPinchGestureChange,
onTap,
onSwipe,
onSwipeSuccess,
onSwipeDown,
}),
[containerWidth, containerHeight, isScrolling, pagerRef, shouldPagerScroll, onPinchGestureChange, onTap, onSwipe, onSwipeSuccess, onSwipeDown],
);

return (
<GestureHandlerRootView style={styles.flex1}>
<AttachmentCarouselPagerContext.Provider
value={{
canvasWidth: containerWidth,
canvasHeight: containerHeight,
isScrolling,
pagerRef,
shouldPagerScroll,
onPinchGestureChange,
onTap,
onSwipe,
onSwipeSuccess,
onSwipeDown,
}}
>
<AttachmentCarouselPagerContext.Provider value={contextValue}>
<AnimatedPagerView
pageMargin={40}
offscreenPageLimit={1}
Expand Down
5 changes: 3 additions & 2 deletions src/components/DragAndDrop/Provider/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _ from 'underscore';
import React, {useRef, useCallback, useEffect} from 'react';
import React, {useRef, useCallback, useEffect, useMemo} from 'react';
import {View} from 'react-native';
import {PortalHost} from '@gorhom/portal';
import Str from 'expensify-common/lib/str';
Expand Down Expand Up @@ -37,8 +37,9 @@ function DragAndDropProvider({children, isDisabled = false, setIsDraggingOver =
setIsDraggingOver(isDraggingOver);
}, [isDraggingOver, setIsDraggingOver]);

const contextValue = useMemo(() => ({isDraggingOver, setOnDropHandler, dropZoneID: dropZoneID.current}), [isDraggingOver, setOnDropHandler]);
return (
<DragAndDropContext.Provider value={{isDraggingOver, setOnDropHandler, dropZoneID: dropZoneID.current}}>
<DragAndDropContext.Provider value={contextValue}>
<View
ref={(e) => (dropZone.current = e)}
style={[styles.flex1, styles.w100, styles.h100]}
Expand Down
21 changes: 10 additions & 11 deletions src/components/PopoverProvider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,18 +118,17 @@ function PopoverContextProvider(props) {
[closePopover],
);

return (
<PopoverContext.Provider
value={{
onOpen,
close: closePopover,
popover: activePopoverRef.current,
isOpen,
}}
>
{props.children}
</PopoverContext.Provider>
const contextValue = React.useMemo(
() => ({
onOpen,
close: closePopover,
popover: activePopoverRef.current,
isOpen,
}),
[onOpen, closePopover, isOpen],
);

return <PopoverContext.Provider value={contextValue}>{props.children}</PopoverContext.Provider>;
}

PopoverContextProvider.defaultProps = defaultProps;
Expand Down
21 changes: 10 additions & 11 deletions src/components/PopoverProvider/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,17 @@ const PopoverContext = React.createContext({
});

function PopoverContextProvider(props) {
return (
<PopoverContext.Provider
value={{
onOpen: () => {},
close: () => {},
popover: {},
isOpen: false,
}}
>
{props.children}
</PopoverContext.Provider>
const contextValue = React.useMemo(
() => ({
onOpen: () => {},
close: () => {},
popover: {},
isOpen: false,
}),
[],
);

return <PopoverContext.Provider value={contextValue}>{props.children}</PopoverContext.Provider>;
}

PopoverContextProvider.defaultProps = defaultProps;
Expand Down
19 changes: 10 additions & 9 deletions src/components/ScrollViewWithContext.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useState, useRef} from 'react';
import React, {useState, useRef, useMemo} from 'react';
import {ScrollView} from 'react-native';

const MIN_SMOOTH_SCROLL_EVENT_THROTTLE = 16;
Expand Down Expand Up @@ -27,6 +27,14 @@ function ScrollViewWithContext({onScroll, scrollEventThrottle, children, innerRe
setContentOffsetY(event.nativeEvent.contentOffset.y);
};

const contextValue = useMemo(
() => ({
scrollViewRef,
contentOffsetY,
}),
[scrollViewRef, contentOffsetY],
);

return (
<ScrollView
// eslint-disable-next-line react/jsx-props-no-spreading
Expand All @@ -35,14 +43,7 @@ function ScrollViewWithContext({onScroll, scrollEventThrottle, children, innerRe
onScroll={setContextScrollPosition}
scrollEventThrottle={scrollEventThrottle || MIN_SMOOTH_SCROLL_EVENT_THROTTLE}
>
<ScrollContext.Provider
value={{
scrollViewRef,
contentOffsetY,
}}
>
{children}
</ScrollContext.Provider>
<ScrollContext.Provider value={contextValue}>{children}</ScrollContext.Provider>
</ScrollView>
);
}
Expand Down
10 changes: 8 additions & 2 deletions src/components/withKeyboardState.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {forwardRef, createContext, useEffect, useState} from 'react';
import React, {forwardRef, createContext, useEffect, useState, useMemo} from 'react';
import {Keyboard} from 'react-native';
import PropTypes from 'prop-types';
import getComponentDisplayName from '../libs/getComponentDisplayName';
Expand Down Expand Up @@ -31,7 +31,13 @@ function KeyboardStateProvider(props) {
};
}, []);

return <KeyboardStateContext.Provider value={{isKeyboardShown}}>{children}</KeyboardStateContext.Provider>;
const contextValue = useMemo(
() => ({
isKeyboardShown,
}),
[isKeyboardShown],
);
return <KeyboardStateContext.Provider value={contextValue}>{children}</KeyboardStateContext.Provider>;
}

KeyboardStateProvider.propTypes = keyboardStateProviderPropTypes;
Expand Down
46 changes: 19 additions & 27 deletions src/components/withWindowDimensions/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, {forwardRef, createContext, useState, useEffect} from 'react';
import React, {forwardRef, createContext, useState, useEffect, useMemo} from 'react';
import PropTypes from 'prop-types';
import lodashDebounce from 'lodash/debounce';
import {Dimensions} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import getComponentDisplayName from '../../libs/getComponentDisplayName';
import variables from '../../styles/variables';
import getWindowHeightAdjustment from '../../libs/getWindowHeightAdjustment';
Expand Down Expand Up @@ -62,31 +62,23 @@ function WindowDimensionsProvider(props) {
dimensionsEventListener.remove();
};
}, []);

return (
<SafeAreaInsetsContext.Consumer>
{(insets) => {
const isExtraSmallScreenWidth = windowDimension.windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint;
const isSmallScreenWidth = windowDimension.windowWidth <= variables.mobileResponsiveWidthBreakpoint;
const isMediumScreenWidth = !isSmallScreenWidth && windowDimension.windowWidth <= variables.tabletResponsiveWidthBreakpoint;
const isLargeScreenWidth = !isSmallScreenWidth && !isMediumScreenWidth;
return (
<WindowDimensionsContext.Provider
value={{
windowHeight: windowDimension.windowHeight + getWindowHeightAdjustment(insets),
windowWidth: windowDimension.windowWidth,
isExtraSmallScreenWidth,
isSmallScreenWidth,
isMediumScreenWidth,
isLargeScreenWidth,
}}
>
{props.children}
</WindowDimensionsContext.Provider>
);
}}
</SafeAreaInsetsContext.Consumer>
);
const insets = useSafeAreaInsets();
const adjustment = getWindowHeightAdjustment(insets);
const contextValue = useMemo(() => {
const isExtraSmallScreenWidth = windowDimension.windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint;
const isSmallScreenWidth = windowDimension.windowWidth <= variables.mobileResponsiveWidthBreakpoint;
const isMediumScreenWidth = !isSmallScreenWidth && windowDimension.windowWidth <= variables.tabletResponsiveWidthBreakpoint;
const isLargeScreenWidth = !isSmallScreenWidth && !isMediumScreenWidth;
return {
windowHeight: windowDimension.windowHeight + adjustment,
windowWidth: windowDimension.windowWidth,
isExtraSmallScreenWidth,
isSmallScreenWidth,
isMediumScreenWidth,
isLargeScreenWidth,
};
}, [windowDimension.windowHeight, windowDimension.windowWidth, adjustment]);
return <WindowDimensionsContext.Provider value={contextValue}>{props.children}</WindowDimensionsContext.Provider>;
}

WindowDimensionsProvider.propTypes = windowDimensionsProviderPropTypes;
Expand Down
43 changes: 16 additions & 27 deletions src/components/withWindowDimensions/index.native.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {forwardRef, createContext, useState, useEffect} from 'react';
import React, {forwardRef, createContext, useState, useEffect, useMemo} from 'react';
import PropTypes from 'prop-types';
import {Dimensions} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import getComponentDisplayName from '../../libs/getComponentDisplayName';
import variables from '../../styles/variables';
import getWindowHeightAdjustment from '../../libs/getWindowHeightAdjustment';
Expand Down Expand Up @@ -60,31 +60,20 @@ function WindowDimensionsProvider(props) {
dimensionsEventListener.remove();
};
}, []);

return (
<SafeAreaInsetsContext.Consumer>
{(insets) => {
const isExtraSmallScreenWidth = windowDimension.windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint;
const isSmallScreenWidth = true;
const isMediumScreenWidth = false;
const isLargeScreenWidth = false;
return (
<WindowDimensionsContext.Provider
value={{
windowHeight: windowDimension.windowHeight + getWindowHeightAdjustment(insets),
windowWidth: windowDimension.windowWidth,
isExtraSmallScreenWidth,
isSmallScreenWidth,
isMediumScreenWidth,
isLargeScreenWidth,
}}
>
{props.children}
</WindowDimensionsContext.Provider>
);
}}
</SafeAreaInsetsContext.Consumer>
);
const insets = useSafeAreaInsets();
const adjustment = getWindowHeightAdjustment(insets);
const contextValue = useMemo(() => {
const isExtraSmallScreenWidth = windowDimension.windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint;
return {
windowHeight: windowDimension.windowHeight + adjustment,
windowWidth: windowDimension.windowWidth,
isExtraSmallScreenWidth,
isSmallScreenWidth: true,
isMediumScreenWidth: false,
isLargeScreenWidth: false,
};
}, [windowDimension.windowHeight, windowDimension.windowWidth, adjustment]);
return <WindowDimensionsContext.Provider value={contextValue}>{props.children}</WindowDimensionsContext.Provider>;
}

WindowDimensionsProvider.propTypes = windowDimensionsProviderPropTypes;
Expand Down
28 changes: 12 additions & 16 deletions src/pages/home/report/ReportActionItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,16 @@ function ReportActionItem(props) {
[props.report, props.action, props.emojiReactions],
);

const contextValue = useMemo(
() => ({
anchor: popoverAnchorRef,
report: props.report,
action: props.action,
checkIfContextMenuActive: toggleContextMenuFromActiveReportAction,
}),
[props.report, props.action, toggleContextMenuFromActiveReportAction],
);

/**
* Get the content of ReportActionItem
* @param {Boolean} hovered whether the ReportActionItem is hovered
Expand Down Expand Up @@ -404,14 +414,7 @@ function ReportActionItem(props) {
} else {
const hasBeenFlagged = !_.contains([CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING], moderationDecision);
children = (
<ShowContextMenuContext.Provider
value={{
anchor: popoverAnchorRef,
report: props.report,
action: props.action,
checkIfContextMenuActive: toggleContextMenuFromActiveReportAction,
}}
>
<ShowContextMenuContext.Provider value={contextValue}>
{!props.draftMessage ? (
<View style={props.displayAsGroup && hasBeenFlagged ? styles.blockquote : {}}>
<ReportActionItemMessage
Expand Down Expand Up @@ -558,14 +561,7 @@ function ReportActionItem(props) {
const parentReportAction = ReportActionsUtils.getParentReportAction(props.report);
if (ReportActionsUtils.isTransactionThread(parentReportAction)) {
content = (
<ShowContextMenuContext.Provider
value={{
anchor: popoverAnchorRef,
report: props.report,
action: props.action,
checkIfContextMenuActive: toggleContextMenuFromActiveReportAction,
}}
>
<ShowContextMenuContext.Provider value={contextValue}>
<MoneyRequestView
report={props.report}
shouldShowHorizontalRule={!props.shouldHideThreadDividerLine}
Expand Down
Loading

0 comments on commit 2b98d2b

Please sign in to comment.