diff --git a/.eslintrc.js b/.eslintrc.js index 75a74ed371c4..78683b043f50 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -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', { diff --git a/src/components/AnimatedStep/AnimatedStepProvider.js b/src/components/AnimatedStep/AnimatedStepProvider.js index 280fbd1a2776..86d40b5bddeb 100644 --- a/src/components/AnimatedStep/AnimatedStepProvider.js +++ b/src/components/AnimatedStep/AnimatedStepProvider.js @@ -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'; @@ -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 {children}; + return {children}; } AnimatedStepProvider.propTypes = propTypes; diff --git a/src/components/Attachments/AttachmentCarousel/Pager/index.js b/src/components/Attachments/AttachmentCarousel/Pager/index.js index 9779963dfc4a..d10a5abad6b7 100644 --- a/src/components/Attachments/AttachmentCarousel/Pager/index.js +++ b/src/components/Attachments/AttachmentCarousel/Pager/index.js @@ -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'; @@ -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 ( - + ({isDraggingOver, setOnDropHandler, dropZoneID: dropZoneID.current}), [isDraggingOver, setOnDropHandler]); return ( - + (dropZone.current = e)} style={[styles.flex1, styles.w100, styles.h100]} diff --git a/src/components/PopoverProvider/index.js b/src/components/PopoverProvider/index.js index efa230d920d5..15ad5da74595 100644 --- a/src/components/PopoverProvider/index.js +++ b/src/components/PopoverProvider/index.js @@ -111,18 +111,17 @@ function PopoverContextProvider(props) { [closePopover], ); - return ( - - {props.children} - + const contextValue = React.useMemo( + () => ({ + onOpen, + close: closePopover, + popover: activePopoverRef.current, + isOpen, + }), + [onOpen, closePopover, isOpen], ); + + return {props.children}; } PopoverContextProvider.defaultProps = defaultProps; diff --git a/src/components/PopoverProvider/index.native.js b/src/components/PopoverProvider/index.native.js index f34abcb1fa62..e4da13752b6d 100644 --- a/src/components/PopoverProvider/index.native.js +++ b/src/components/PopoverProvider/index.native.js @@ -15,18 +15,17 @@ const PopoverContext = React.createContext({ }); function PopoverContextProvider(props) { - return ( - {}, - close: () => {}, - popover: {}, - isOpen: false, - }} - > - {props.children} - + const contextValue = React.useMemo( + () => ({ + onOpen: () => {}, + close: () => {}, + popover: {}, + isOpen: false, + }), + [], ); + + return {props.children}; } PopoverContextProvider.defaultProps = defaultProps; diff --git a/src/components/ScrollViewWithContext.js b/src/components/ScrollViewWithContext.js index bf0e7c6d62e8..1d183e250767 100644 --- a/src/components/ScrollViewWithContext.js +++ b/src/components/ScrollViewWithContext.js @@ -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; @@ -27,6 +27,14 @@ function ScrollViewWithContext({onScroll, scrollEventThrottle, children, innerRe setContentOffsetY(event.nativeEvent.contentOffset.y); }; + const contextValue = useMemo( + () => ({ + scrollViewRef, + contentOffsetY, + }), + [scrollViewRef, contentOffsetY], + ); + return ( - - {children} - + {children} ); } diff --git a/src/components/withKeyboardState.js b/src/components/withKeyboardState.js index 8ddf667b4e30..3154f7e98d67 100755 --- a/src/components/withKeyboardState.js +++ b/src/components/withKeyboardState.js @@ -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'; @@ -31,7 +31,13 @@ function KeyboardStateProvider(props) { }; }, []); - return {children}; + const contextValue = useMemo( + () => ({ + isKeyboardShown, + }), + [isKeyboardShown], + ); + return {children}; } KeyboardStateProvider.propTypes = keyboardStateProviderPropTypes; diff --git a/src/components/withWindowDimensions/index.js b/src/components/withWindowDimensions/index.js index 37d5c94688a2..16e5985e0985 100644 --- a/src/components/withWindowDimensions/index.js +++ b/src/components/withWindowDimensions/index.js @@ -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'; @@ -62,31 +62,23 @@ function WindowDimensionsProvider(props) { dimensionsEventListener.remove(); }; }, []); - - return ( - - {(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 ( - - {props.children} - - ); - }} - - ); + 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 {props.children}; } WindowDimensionsProvider.propTypes = windowDimensionsProviderPropTypes; diff --git a/src/components/withWindowDimensions/index.native.js b/src/components/withWindowDimensions/index.native.js index e147a20c9f4e..363196b3fd4d 100644 --- a/src/components/withWindowDimensions/index.native.js +++ b/src/components/withWindowDimensions/index.native.js @@ -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'; @@ -60,31 +60,20 @@ function WindowDimensionsProvider(props) { dimensionsEventListener.remove(); }; }, []); - - return ( - - {(insets) => { - const isExtraSmallScreenWidth = windowDimension.windowWidth <= variables.extraSmallMobileResponsiveWidthBreakpoint; - const isSmallScreenWidth = true; - const isMediumScreenWidth = false; - const isLargeScreenWidth = false; - return ( - - {props.children} - - ); - }} - - ); + 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 {props.children}; } WindowDimensionsProvider.propTypes = windowDimensionsProviderPropTypes; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index d0e84499a443..db5ac43d9d34 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -274,6 +274,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 @@ -366,14 +376,7 @@ function ReportActionItem(props) { } else { const hasBeenFlagged = !_.contains([CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING], moderationDecision); children = ( - + {!props.draftMessage ? ( + ({setStep: handleSetStep}), [handleSetStep]); const renderStep = () => { switch (currentStep) { @@ -58,15 +59,7 @@ function TwoFactorAuthSteps({account = defaultAccount}) { } }; - return ( - - {renderStep()} - - ); + return {renderStep()}; } TwoFactorAuthSteps.propTypes = TwoFactorAuthPropTypes;