Skip to content

Commit 87ce5ef

Browse files
authored
Merge pull request Expensify#81986 from software-mansion-labs/perf/migrate-contexts
Split contexts to state and actions - Batch 2
2 parents 85ae7ac + 66b7600 commit 87ce5ef

113 files changed

Lines changed: 1379 additions & 730 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/CONST/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8265,6 +8265,8 @@ const CONST = {
82658265
SEARCH_BUTTON: 'Search-SearchButton',
82668266
USER_SELECTION_CHECKBOX: 'Search-UserSelectionCheckbox',
82678267
TRANSACTION_GROUP_LIST_ITEM: 'Search-TransactionGroupListItem',
8268+
TRANSACTION_LIST_ITEM: 'Search-TransactionListItem',
8269+
REPORT_EXPAND_COLLAPSE: 'Search-ReportExpandCollapse',
82688270
SELECT_ALL_BUTTON: 'Search-SelectAllButton',
82698271
TYPE_MENU_BUTTON: 'Search-TypeMenuButton',
82708272
FILTER_TYPE: 'Search-FilterType',
@@ -8299,7 +8301,6 @@ const CONST = {
82998301
FILTER_POPUP_APPLY_DATE: 'Search-FilterPopupApplyDate',
83008302
FILTER_POPUP_RESET_USER: 'Search-FilterPopupResetUser',
83018303
FILTER_POPUP_APPLY_USER: 'Search-FilterPopupApplyUser',
8302-
TRANSACTION_LIST_ITEM: 'Search-TransactionListItem',
83038304
TRANSACTION_LIST_ITEM_CHECKBOX: 'Search-TransactionListItemCheckbox',
83048305
EXPANDED_TRANSACTION_ROW: 'Search-ExpandedTransactionRow',
83058306
EXPANDED_TRANSACTION_ROW_CHECKBOX: 'Search-ExpandedTransactionRowCheckbox',

src/components/AmountForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {ForwardedRef} from 'react';
22
import React from 'react';
3-
import useCurrencyList from '@hooks/useCurrencyList';
3+
import {useCurrencyListActions} from '@hooks/useCurrencyList';
44
import useLocalize from '@hooks/useLocalize';
55
import useThemeStyles from '@hooks/useThemeStyles';
66
import {getLocalizedCurrencySymbol} from '@libs/CurrencyUtils';
@@ -84,7 +84,7 @@ function AmountForm({
8484
}: AmountFormProps) {
8585
const {preferredLocale} = useLocalize();
8686
const styles = useThemeStyles();
87-
const {getCurrencyDecimals} = useCurrencyList();
87+
const {getCurrencyDecimals} = useCurrencyListActions();
8888
const decimals = decimalsProp ?? getCurrencyDecimals(currency);
8989

9090
return (

src/components/Attachments/AttachmentCarousel/AttachmentCarouselView/index.tsx

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import Animated, {scrollTo, useAnimatedRef, useSharedValue} from 'react-native-r
88
import CarouselActions from '@components/Attachments/AttachmentCarousel/CarouselActions';
99
import CarouselButtons from '@components/Attachments/AttachmentCarousel/CarouselButtons';
1010
import CarouselItem from '@components/Attachments/AttachmentCarousel/CarouselItem';
11-
import AttachmentCarouselPagerContext from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext';
11+
import {AttachmentCarouselPagerActionsContext, AttachmentCarouselPagerStateContext} from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext';
12+
import type {AttachmentCarouselPagerActionsContextType, AttachmentCarouselPagerStateContextType} from '@components/Attachments/AttachmentCarousel/Pager/types';
1213
import type {UpdatePageProps} from '@components/Attachments/AttachmentCarousel/types';
1314
import useCarouselContextEvents from '@components/Attachments/AttachmentCarousel/useCarouselContextEvents';
1415
import type {Attachment, AttachmentSource} from '@components/Attachments/types';
@@ -149,19 +150,25 @@ function AttachmentCarouselView({
149150
[cellWidth],
150151
);
151152

152-
const context = useMemo(
153+
const stateValue = useMemo<AttachmentCarouselPagerStateContextType>(
153154
() => ({
154155
pagerItems: [{source, index: 0, isActive: true}],
155156
activePage: 0,
156157
pagerRef,
157158
isPagerScrolling,
158159
isScrollEnabled,
160+
}),
161+
[source, isPagerScrolling, isScrollEnabled],
162+
);
163+
164+
const actionsValue = useMemo<AttachmentCarouselPagerActionsContextType>(
165+
() => ({
159166
onTap: handleTap,
160167
onScaleChanged: handleScaleChange,
161168
onSwipeDown,
162169
onAttachmentError,
163170
}),
164-
[onAttachmentError, source, isPagerScrolling, isScrollEnabled, handleTap, handleScaleChange, onSwipeDown],
171+
[handleTap, handleScaleChange, onSwipeDown, onAttachmentError],
165172
);
166173

167174
/** Defines how a single attachment should be rendered */
@@ -255,31 +262,33 @@ function AttachmentCarouselView({
255262
autoHideArrow={autoHideArrows}
256263
cancelAutoHideArrow={cancelAutoHideArrow}
257264
/>
258-
<AttachmentCarouselPagerContext.Provider value={context}>
259-
<DeviceAwareGestureDetector
260-
canUseTouchScreen={canUseTouchScreen}
261-
gesture={pan}
262-
>
263-
<Animated.FlatList
264-
keyboardShouldPersistTaps="handled"
265-
horizontal
266-
showsHorizontalScrollIndicator={false}
267-
// scrolling is controlled by the pan gesture
268-
scrollEnabled={false}
269-
ref={scrollRef}
270-
initialScrollIndex={page}
271-
initialNumToRender={3}
272-
windowSize={5}
273-
maxToRenderPerBatch={CONST.MAX_TO_RENDER_PER_BATCH.CAROUSEL}
274-
data={attachments}
275-
renderItem={renderItem}
276-
getItemLayout={getItemLayout}
277-
keyExtractor={extractItemKey}
278-
viewabilityConfig={viewabilityConfig}
279-
onViewableItemsChanged={updatePage}
280-
/>
281-
</DeviceAwareGestureDetector>
282-
</AttachmentCarouselPagerContext.Provider>
265+
<AttachmentCarouselPagerStateContext.Provider value={stateValue}>
266+
<AttachmentCarouselPagerActionsContext.Provider value={actionsValue}>
267+
<DeviceAwareGestureDetector
268+
canUseTouchScreen={canUseTouchScreen}
269+
gesture={pan}
270+
>
271+
<Animated.FlatList
272+
keyboardShouldPersistTaps="handled"
273+
horizontal
274+
showsHorizontalScrollIndicator={false}
275+
// scrolling is controlled by the pan gesture
276+
scrollEnabled={false}
277+
ref={scrollRef}
278+
initialScrollIndex={page}
279+
initialNumToRender={3}
280+
windowSize={5}
281+
maxToRenderPerBatch={CONST.MAX_TO_RENDER_PER_BATCH.CAROUSEL}
282+
data={attachments}
283+
renderItem={renderItem}
284+
getItemLayout={getItemLayout}
285+
keyExtractor={extractItemKey}
286+
viewabilityConfig={viewabilityConfig}
287+
onViewableItemsChanged={updatePage}
288+
/>
289+
</DeviceAwareGestureDetector>
290+
</AttachmentCarouselPagerActionsContext.Provider>
291+
</AttachmentCarouselPagerStateContext.Provider>
283292
<CarouselActions onCycleThroughAttachments={cycleThroughAttachments} />
284293
</>
285294
)}
Lines changed: 12 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,16 @@
1-
import type {ForwardedRef} from 'react';
2-
import {createContext} from 'react';
3-
import type {GestureType} from 'react-native-gesture-handler';
4-
import type PagerView from 'react-native-pager-view';
5-
import type {SharedValue} from 'react-native-reanimated';
6-
import type {Attachment, AttachmentSource} from '@components/Attachments/types';
1+
import {createContext, useContext} from 'react';
2+
import type {AttachmentCarouselPagerActionsContextType, AttachmentCarouselPagerStateContextType} from './types';
73

8-
/** The pager items array is used within the pager to render and navigate between the images */
9-
type AttachmentCarouselPagerItems = Pick<Attachment, 'attachmentID'> & {
10-
/** The source of the image is used to identify each attachment/page in the pager */
11-
source: AttachmentSource;
4+
const AttachmentCarouselPagerStateContext = createContext<AttachmentCarouselPagerStateContextType | null>(null);
5+
const AttachmentCarouselPagerActionsContext = createContext<AttachmentCarouselPagerActionsContextType | null>(null);
126

13-
/** URL to preview-sized attachment that is also used for the thumbnail */
14-
previewSource?: AttachmentSource;
7+
function useAttachmentCarouselPagerState(): AttachmentCarouselPagerStateContextType | null {
8+
return useContext(AttachmentCarouselPagerStateContext);
9+
}
1510

16-
/** The index of the pager item determines the order of the images in the pager */
17-
index: number;
11+
function useAttachmentCarouselPagerActions(): AttachmentCarouselPagerActionsContextType | null {
12+
return useContext(AttachmentCarouselPagerActionsContext);
13+
}
1814

19-
/** The active state of the pager item determines whether the image is currently transformable with pinch, pan and tap gestures */
20-
isActive: boolean;
21-
};
22-
23-
type AttachmentCarouselPagerContextValue = {
24-
/** List of attachments displayed in the pager */
25-
pagerItems: AttachmentCarouselPagerItems[];
26-
27-
/** Index of the currently active page */
28-
activePage: number;
29-
30-
/** Ref to the active attachment */
31-
pagerRef?: ForwardedRef<PagerView | GestureType>;
32-
33-
/** Indicates if the pager is currently scrolling */
34-
isPagerScrolling: SharedValue<boolean>;
35-
36-
/** Indicates if scrolling is enabled for the attachment */
37-
isScrollEnabled: SharedValue<boolean>;
38-
39-
/** Function to call after a tap event */
40-
onTap?: (shouldShowArrows?: boolean) => void;
41-
42-
/** Function to call when the scale changes */
43-
onScaleChanged?: (scale: number) => void;
44-
45-
/** Function to call after a swipe down event */
46-
onSwipeDown?: () => void;
47-
48-
/** Callback for attachment errors */
49-
onAttachmentError?: (source: AttachmentSource, state?: boolean) => void;
50-
51-
/** In case we need a gesture that should work simultaneously with panning in MultiGestureCanvas */
52-
externalGestureHandler?: GestureType;
53-
};
54-
55-
const AttachmentCarouselPagerContext = createContext<AttachmentCarouselPagerContextValue | null>(null);
56-
57-
export default AttachmentCarouselPagerContext;
58-
export type {AttachmentCarouselPagerContextValue};
15+
export {AttachmentCarouselPagerActionsContext, AttachmentCarouselPagerStateContext, useAttachmentCarouselPagerActions, useAttachmentCarouselPagerState};
16+
export type {AttachmentCarouselPagerActionsContextType, AttachmentCarouselPagerItems, AttachmentCarouselPagerStateContextType} from './types';

src/components/Attachments/AttachmentCarousel/Pager/index.tsx

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import CarouselItem from '@components/Attachments/AttachmentCarousel/CarouselIte
99
import useCarouselContextEvents from '@components/Attachments/AttachmentCarousel/useCarouselContextEvents';
1010
import type {Attachment, AttachmentSource} from '@components/Attachments/types';
1111
import useThemeStyles from '@hooks/useThemeStyles';
12-
import AttachmentCarouselPagerContext from './AttachmentCarouselPagerContext';
12+
import {AttachmentCarouselPagerActionsContext, AttachmentCarouselPagerStateContext} from './AttachmentCarouselPagerContext';
13+
import type {AttachmentCarouselPagerActionsContextType, AttachmentCarouselPagerStateContextType} from './types';
1314
import usePageScrollHandler from './usePageScrollHandler';
1415

1516
const AnimatedPagerView = Animated.createAnimatedComponent(PagerView);
@@ -85,20 +86,26 @@ function AttachmentCarouselPager({items, activeAttachmentID, initialPage, setSho
8586

8687
const nativeGestureHandler = Gesture.Native();
8788

88-
const contextValue = useMemo(
89+
const stateValue = useMemo<AttachmentCarouselPagerStateContextType>(
8990
() => ({
9091
pagerItems,
9192
activePage: activePageIndex,
9293
isPagerScrolling,
9394
isScrollEnabled,
9495
pagerRef,
96+
externalGestureHandler: nativeGestureHandler,
97+
}),
98+
[pagerItems, activePageIndex, isPagerScrolling, isScrollEnabled, nativeGestureHandler],
99+
);
100+
101+
const actionsValue = useMemo<AttachmentCarouselPagerActionsContextType>(
102+
() => ({
95103
onTap: handleTap,
96104
onSwipeDown,
97105
onScaleChanged: handleScaleChange,
98106
onAttachmentError,
99-
externalGestureHandler: nativeGestureHandler,
100107
}),
101-
[pagerItems, activePageIndex, isPagerScrolling, isScrollEnabled, handleTap, onSwipeDown, handleScaleChange, nativeGestureHandler, onAttachmentError],
108+
[handleTap, onSwipeDown, handleScaleChange, onAttachmentError],
102109
);
103110

104111
const animatedProps = useAnimatedProps(() => ({
@@ -133,22 +140,24 @@ function AttachmentCarouselPager({items, activeAttachmentID, initialPage, setSho
133140
));
134141

135142
return (
136-
<AttachmentCarouselPagerContext.Provider value={contextValue}>
137-
<GestureDetector gesture={nativeGestureHandler}>
138-
<AnimatedPagerView
139-
pageMargin={40}
140-
offscreenPageLimit={1}
141-
onPageScroll={pageScrollHandler}
142-
onPageSelected={onPageSelected}
143-
style={styles.flex1}
144-
initialPage={initialPage}
145-
animatedProps={animatedProps}
146-
ref={pagerRef}
147-
>
148-
{carouselItems}
149-
</AnimatedPagerView>
150-
</GestureDetector>
151-
</AttachmentCarouselPagerContext.Provider>
143+
<AttachmentCarouselPagerStateContext.Provider value={stateValue}>
144+
<AttachmentCarouselPagerActionsContext.Provider value={actionsValue}>
145+
<GestureDetector gesture={nativeGestureHandler}>
146+
<AnimatedPagerView
147+
pageMargin={40}
148+
offscreenPageLimit={1}
149+
onPageScroll={pageScrollHandler}
150+
onPageSelected={onPageSelected}
151+
style={styles.flex1}
152+
initialPage={initialPage}
153+
animatedProps={animatedProps}
154+
ref={pagerRef}
155+
>
156+
{carouselItems}
157+
</AnimatedPagerView>
158+
</GestureDetector>
159+
</AttachmentCarouselPagerActionsContext.Provider>
160+
</AttachmentCarouselPagerStateContext.Provider>
152161
);
153162
}
154163

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import type {ForwardedRef} from 'react';
2+
import type {GestureType} from 'react-native-gesture-handler';
3+
import type PagerView from 'react-native-pager-view';
4+
import type {SharedValue} from 'react-native-reanimated';
5+
import type {Attachment, AttachmentSource} from '@components/Attachments/types';
6+
7+
/** The pager items array is used within the pager to render and navigate between the images */
8+
type AttachmentCarouselPagerItems = Pick<Attachment, 'attachmentID'> & {
9+
/** The source of the image is used to identify each attachment/page in the pager */
10+
source: AttachmentSource;
11+
12+
/** URL to preview-sized attachment that is also used for the thumbnail */
13+
previewSource?: AttachmentSource;
14+
15+
/** The index of the pager item determines the order of the images in the pager */
16+
index: number;
17+
18+
/** The active state of the pager item determines whether the image is currently transformable with pinch, pan and tap gestures */
19+
isActive: boolean;
20+
};
21+
22+
type AttachmentCarouselPagerStateContextType = {
23+
/** List of attachments displayed in the pager */
24+
pagerItems: AttachmentCarouselPagerItems[];
25+
26+
/** Index of the currently active page */
27+
activePage: number;
28+
29+
/** Ref to the active attachment */
30+
pagerRef?: ForwardedRef<PagerView | GestureType>;
31+
32+
/** Indicates if the pager is currently scrolling */
33+
isPagerScrolling: SharedValue<boolean>;
34+
35+
/** Indicates if scrolling is enabled for the attachment */
36+
isScrollEnabled: SharedValue<boolean>;
37+
38+
/** In case we need a gesture that should work simultaneously with panning in MultiGestureCanvas */
39+
externalGestureHandler?: GestureType;
40+
};
41+
42+
type AttachmentCarouselPagerActionsContextType = {
43+
/** Function to call after a tap event */
44+
onTap?: (shouldShowArrows?: boolean) => void;
45+
46+
/** Function to call when the scale changes */
47+
onScaleChanged?: (scale: number) => void;
48+
49+
/** Function to call after a swipe down event */
50+
onSwipeDown?: () => void;
51+
52+
/** Callback for attachment errors */
53+
onAttachmentError?: (source: AttachmentSource, state?: boolean) => void;
54+
};
55+
56+
export type {AttachmentCarouselPagerItems, AttachmentCarouselPagerStateContextType, AttachmentCarouselPagerActionsContextType};

src/components/Attachments/AttachmentView/AttachmentViewPdf/BaseAttachmentViewPdf.tsx

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import React, {memo, useCallback, useContext, useEffect} from 'react';
1+
import React, {memo, useCallback, useEffect} from 'react';
22
import type {GestureResponderEvent} from 'react-native';
3-
import AttachmentCarouselPagerContext from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext';
3+
import {useAttachmentCarouselPagerActions, useAttachmentCarouselPagerState} from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext';
44
import PDFView from '@components/PDFView';
55
import type AttachmentViewPdfProps from './types';
66

@@ -16,14 +16,15 @@ function BaseAttachmentViewPdf({
1616
isUsedAsChatAttachment,
1717
onLoadError,
1818
}: AttachmentViewPdfProps) {
19-
const attachmentCarouselPagerContext = useContext(AttachmentCarouselPagerContext);
20-
const isScrollEnabled = attachmentCarouselPagerContext === null ? undefined : attachmentCarouselPagerContext.isScrollEnabled;
19+
const state = useAttachmentCarouselPagerState();
20+
const actions = useAttachmentCarouselPagerActions();
21+
const isScrollEnabled = state === null ? undefined : state.isScrollEnabled;
2122

2223
useEffect(() => {
23-
if (!attachmentCarouselPagerContext) {
24+
if (!actions) {
2425
return;
2526
}
26-
attachmentCarouselPagerContext.onScaleChanged?.(1);
27+
actions.onScaleChanged?.(1);
2728
// eslint-disable-next-line react-hooks/exhaustive-deps -- we just want to call this function when component is mounted
2829
}, []);
2930

@@ -39,11 +40,11 @@ function BaseAttachmentViewPdf({
3940
}
4041

4142
// When a pdf is shown in a carousel, we want to disable the pager scroll when the pdf is zoomed in
42-
if (attachmentCarouselPagerContext?.pagerRef) {
43-
attachmentCarouselPagerContext.onScaleChanged?.(newScale);
43+
if (state?.pagerRef && actions) {
44+
actions.onScaleChanged?.(newScale);
4445
}
4546
},
46-
[attachmentCarouselPagerContext, onScaleChangedProp],
47+
[state?.pagerRef, actions, onScaleChangedProp],
4748
);
4849

4950
/**
@@ -58,11 +59,11 @@ function BaseAttachmentViewPdf({
5859
onPressProp(event);
5960
}
6061

61-
if (attachmentCarouselPagerContext !== null && isScrollEnabled?.get()) {
62-
attachmentCarouselPagerContext.onTap?.();
62+
if (state !== null && actions && isScrollEnabled?.get()) {
63+
actions.onTap?.();
6364
}
6465
},
65-
[attachmentCarouselPagerContext, isScrollEnabled, onPressProp],
66+
[state, actions, isScrollEnabled, onPressProp],
6667
);
6768

6869
return (

0 commit comments

Comments
 (0)