Skip to content

Commit

Permalink
Optimized context usages and set up eslint rule to prevent unnecessar…
Browse files Browse the repository at this point in the history
…y rerender in the future
  • Loading branch information
sebryu committed Sep 30, 2023
1 parent 7c86d09 commit 30513ad
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 107 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ module.exports = {
overrides: [
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
plugins: ['react'],
rules: {
'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
39 changes: 26 additions & 13 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,21 +126,34 @@ 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,
}}
value={contextValue}
>
<AnimatedPagerView
pageMargin={40}
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
16 changes: 8 additions & 8 deletions src/components/PopoverProvider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,15 @@ function PopoverContextProvider(props) {
[closePopover],
);

const contextValue = React.useMemo(() => ({
onOpen,
close: closePopover,
popover: activePopoverRef.current,
isOpen,
}), [onOpen, closePopover, isOpen]);

return (
<PopoverContext.Provider
value={{
onOpen,
close: closePopover,
popover: activePopoverRef.current,
isOpen,
}}
>
<PopoverContext.Provider value={contextValue}>
{props.children}
</PopoverContext.Provider>
);
Expand Down
16 changes: 8 additions & 8 deletions src/components/PopoverProvider/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ const PopoverContext = React.createContext({
});

function PopoverContextProvider(props) {
const contextValue = React.useMemo(() => ({
onOpen: () => {},
close: () => {},
popover: {},
isOpen: false,
}), []);

return (
<PopoverContext.Provider
value={{
onOpen: () => {},
close: () => {},
popover: {},
isOpen: false,
}}
>
<PopoverContext.Provider value={contextValue}>
{props.children}
</PopoverContext.Provider>
);
Expand Down
12 changes: 7 additions & 5 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,11 @@ 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 @@ -36,10 +41,7 @@ function ScrollViewWithContext({onScroll, scrollEventThrottle, children, innerRe
scrollEventThrottle={scrollEventThrottle || MIN_SMOOTH_SCROLL_EVENT_THROTTLE}
>
<ScrollContext.Provider
value={{
scrollViewRef,
contentOffsetY,
}}
value={contextValue}
>
{children}
</ScrollContext.Provider>
Expand Down
7 changes: 5 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,10 @@ 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
48 changes: 23 additions & 25 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,30 +62,28 @@ function WindowDimensionsProvider(props) {
dimensionsEventListener.remove();
};
}, []);

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 (
<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>
<WindowDimensionsContext.Provider
value={contextValue}
>
{props.children}
</WindowDimensionsContext.Provider>
);
}

Expand Down
45 changes: 20 additions & 25 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,30 +60,25 @@ function WindowDimensionsProvider(props) {
dimensionsEventListener.remove();
};
}, []);

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 (
<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>
<WindowDimensionsContext.Provider
value={contextValue}
>
{props.children}
</WindowDimensionsContext.Provider>
);
}

Expand Down
23 changes: 10 additions & 13 deletions src/pages/home/report/ReportActionItem.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _ from 'underscore';
import lodashGet from 'lodash/get';
import React, {useState, useRef, useEffect, memo, useCallback, useContext} from 'react';
import React, {useState, useRef, useEffect, memo, useCallback, useContext, useMemo} from 'react';
import {InteractionManager, View} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
Expand Down Expand Up @@ -263,6 +263,13 @@ 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 @@ -356,12 +363,7 @@ function ReportActionItem(props) {
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,
}}
value={contextValue}
>
{!props.draftMessage ? (
<View style={props.displayAsGroup && hasBeenFlagged ? styles.blockquote : {}}>
Expand Down Expand Up @@ -504,12 +506,7 @@ function ReportActionItem(props) {
if (ReportActionsUtils.isTransactionThread(parentReportAction)) {
return (
<ShowContextMenuContext.Provider
value={{
anchor: popoverAnchorRef,
report: props.report,
action: props.action,
checkIfContextMenuActive: toggleContextMenuFromActiveReportAction,
}}
value={contextValue}
>
<MoneyRequestView
report={props.report}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useEffect, useState} from 'react';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
import CodesStep from './Steps/CodesStep';
import DisabledStep from './Steps/DisabledStep';
Expand Down Expand Up @@ -40,6 +40,7 @@ function TwoFactorAuthSteps({account = defaultAccount}) {
},
[setAnimationDirection],
);
const contextValue = useMemo(() => ({setStep: handleSetStep}), [handleSetStep]);

const renderStep = () => {
switch (currentStep) {
Expand All @@ -60,9 +61,7 @@ function TwoFactorAuthSteps({account = defaultAccount}) {

return (
<TwoFactorAuthContext.Provider
value={{
setStep: handleSetStep,
}}
value={contextValue}
>
{renderStep()}
</TwoFactorAuthContext.Provider>
Expand Down

0 comments on commit 30513ad

Please sign in to comment.