Skip to content

Commit 2b86fbc

Browse files
committed
perf: improve animation performance
1 parent a1f9d5b commit 2b86fbc

File tree

9 files changed

+42
-35
lines changed

9 files changed

+42
-35
lines changed

package/src/components/MessageInput/MessageComposer.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
55
import Animated, {
66
Extrapolation,
77
interpolate,
8-
LinearTransition,
98
useAnimatedStyle,
109
useSharedValue,
1110
} from 'react-native-reanimated';
@@ -54,6 +53,7 @@ import { useStateStore } from '../../hooks/useStateStore';
5453
import { AudioRecorderManagerState } from '../../state-store/audio-recorder-manager';
5554
import { MessageInputHeightState } from '../../state-store/message-input-height-store';
5655
import { primitives } from '../../theme';
56+
import { transitions } from '../../utils/transitions';
5757
import { type TextInputOverrideComponent } from '../AutoCompleteInput/AutoCompleteInput';
5858
import { CreatePoll } from '../Poll/CreatePollContent';
5959
import { PortalWhileClosingView } from '../UIComponents/PortalWhileClosingView';
@@ -383,7 +383,7 @@ const MessageComposerWithContext = (props: MessageComposerPropsWithContext) => {
383383
]
384384
: null
385385
}
386-
layout={LinearTransition.duration(200)}
386+
layout={transitions.layout200}
387387
>
388388
<PortalWhileClosingView portalHostName='overlay-composer' portalName='message-composer'>
389389
<View
@@ -419,7 +419,7 @@ const MessageComposerWithContext = (props: MessageComposerPropsWithContext) => {
419419
<View style={[styles.container, container]}>
420420
<MessageComposerLeadingView />
421421
<Animated.View
422-
layout={LinearTransition.duration(200)}
422+
layout={transitions.layout200}
423423
style={[
424424
styles.inputBoxWrapper,
425425
messageInputFloating ? [styles.shadow, inputFloatingContainer] : null,
@@ -438,7 +438,7 @@ const MessageComposerWithContext = (props: MessageComposerPropsWithContext) => {
438438

439439
<Animated.View
440440
style={[styles.inputContainer, inputContainer]}
441-
layout={LinearTransition.duration(200)}
441+
layout={transitions.layout200}
442442
>
443443
{!isRecordingStateIdle ? (
444444
<AudioRecorder slideToCancelStyle={slideToCancelAnimatedStyle} />

package/src/components/MessageInput/MessageComposerLeadingView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import React from 'react';
22
import { StyleSheet } from 'react-native';
33

4-
import Animated, { LinearTransition } from 'react-native-reanimated';
4+
import Animated from 'react-native-reanimated';
55

66
import { InputButtons } from './components/InputButtons';
77
import { idleRecordingStateSelector } from './utils/audioRecorderSelectors';
88

99
import { useMessageInputContext } from '../../contexts/messageInputContext/MessageInputContext';
1010
import { useTheme } from '../../contexts/themeContext/ThemeContext';
1111
import { useStateStore } from '../../hooks/useStateStore';
12+
import { transitions } from '../../utils/transitions';
1213

1314
export const MessageComposerLeadingView = () => {
1415
const {
@@ -24,7 +25,7 @@ export const MessageComposerLeadingView = () => {
2425

2526
return isRecordingStateIdle ? (
2627
<Animated.View
27-
layout={LinearTransition.duration(200)}
28+
layout={transitions.layout200}
2829
style={[
2930
styles.inputButtonsContainer,
3031
messageInputFloating ? styles.shadow : null,

package/src/components/MessageInput/MessageInputHeaderView.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useCallback } from 'react';
22
import { StyleSheet } from 'react-native';
33

4-
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated';
4+
import Animated from 'react-native-reanimated';
55

66
import { LinkPreviewList } from './components/LinkPreviewList';
77
import { useHasLinkPreviews } from './hooks/useLinkPreviews';
@@ -17,6 +17,7 @@ import { useMessagesContext } from '../../contexts/messagesContext/MessagesConte
1717
import { useTheme } from '../../contexts/themeContext/ThemeContext';
1818
import { useStateStore } from '../../hooks/useStateStore';
1919
import { primitives } from '../../theme';
20+
import { transitions } from '../../utils/transitions';
2021

2122
export const MessageInputHeaderView = () => {
2223
const {
@@ -42,7 +43,7 @@ export const MessageInputHeaderView = () => {
4243

4344
return isRecordingStateIdle ? (
4445
<Animated.View
45-
layout={LinearTransition.duration(200)}
46+
layout={transitions.layout200}
4647
style={[
4748
styles.contentContainer,
4849
{
@@ -55,7 +56,7 @@ export const MessageInputHeaderView = () => {
5556
]}
5657
>
5758
{editing ? (
58-
<Animated.View entering={FadeIn.duration(200)} exiting={FadeOut.duration(200)}>
59+
<Animated.View entering={transitions.fadeIn200} exiting={transitions.fadeOut200}>
5960
<Reply
6061
mode='edit'
6162
onDismiss={clearEditingState}
@@ -64,7 +65,7 @@ export const MessageInputHeaderView = () => {
6465
</Animated.View>
6566
) : null}
6667
{quotedMessage && !editing ? (
67-
<Animated.View entering={FadeIn.duration(200)} exiting={FadeOut.duration(200)}>
68+
<Animated.View entering={transitions.fadeIn200} exiting={transitions.fadeOut200}>
6869
<Reply onDismiss={editing ? undefined : onDismissReply} mode='reply' />
6970
</Animated.View>
7071
) : null}

package/src/components/MessageInput/MessageInputTrailingView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { StyleSheet } from 'react-native';
33

4-
import Animated, { LinearTransition } from 'react-native-reanimated';
4+
import Animated from 'react-native-reanimated';
55

66
import { OutputButtons } from './components/OutputButtons';
77

@@ -11,6 +11,7 @@ import { useMessageInputContext } from '../../contexts/messageInputContext/Messa
1111
import { useTheme } from '../../contexts/themeContext/ThemeContext';
1212
import { useStateStore } from '../../hooks/useStateStore';
1313
import { primitives } from '../../theme';
14+
import { transitions } from '../../utils/transitions';
1415

1516
export const MessageInputTrailingView = () => {
1617
const {
@@ -25,7 +26,7 @@ export const MessageInputTrailingView = () => {
2526
);
2627
return (recordingStatus === 'idle' || recordingStatus === 'recording') && !micLocked ? (
2728
<Animated.View
28-
layout={LinearTransition.duration(200)}
29+
layout={transitions.layout200}
2930
style={[styles.outputButtonsContainer, outputButtonsContainer]}
3031
>
3132
<OutputButtons />

package/src/components/MessageInput/components/OutputButtons/index.tsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useCallback } from 'react';
22

3-
import Animated, { ZoomIn, ZoomOut } from 'react-native-reanimated';
3+
import Animated from 'react-native-reanimated';
44

55
import { TextComposerState } from 'stream-chat';
66

@@ -21,6 +21,7 @@ import {
2121
useMessageInputContext,
2222
} from '../../../../contexts/messageInputContext/MessageInputContext';
2323
import { useStateStore } from '../../../../hooks/useStateStore';
24+
import { transitions } from '../../../../utils/transitions';
2425
import { AIStates, useAIState } from '../../../AITypingIndicatorView';
2526
import { useIsCooldownActive } from '../../hooks/useIsCooldownActive';
2627

@@ -88,8 +89,8 @@ export const OutputButtonsWithContext = (props: OutputButtonsWithContextProps) =
8889
} else if (editing || command) {
8990
return (
9091
<Animated.View
91-
entering={ZoomIn.duration(200)}
92-
exiting={ZoomOut.duration(200)}
92+
entering={transitions.zoomIn200}
93+
exiting={transitions.zoomOut200}
9394
key='edit-button'
9495
style={editButtonContainer}
9596
>
@@ -99,8 +100,8 @@ export const OutputButtonsWithContext = (props: OutputButtonsWithContextProps) =
99100
} else if (cooldownIsActive) {
100101
return (
101102
<Animated.View
102-
entering={ZoomIn.duration(200)}
103-
exiting={ZoomOut.duration(200)}
103+
entering={transitions.zoomIn200}
104+
exiting={transitions.zoomOut200}
104105
key='cooldown-timer'
105106
style={cooldownButtonContainer}
106107
>
@@ -110,8 +111,8 @@ export const OutputButtonsWithContext = (props: OutputButtonsWithContextProps) =
110111
} else if (audioRecordingEnabled && textIsEmpty && !hasAttachments) {
111112
return (
112113
<Animated.View
113-
entering={ZoomIn.duration(200)}
114-
exiting={ZoomOut.duration(200)}
114+
entering={transitions.zoomIn200}
115+
exiting={transitions.zoomOut200}
115116
key='audio-recording-button'
116117
style={audioRecordingButtonContainer}
117118
>
@@ -121,8 +122,8 @@ export const OutputButtonsWithContext = (props: OutputButtonsWithContextProps) =
121122
} else {
122123
return (
123124
<Animated.View
124-
entering={ZoomIn.duration(200)}
125-
exiting={ZoomOut.duration(200)}
125+
entering={transitions.zoomIn200}
126+
exiting={transitions.zoomOut200}
126127
key='send-button'
127128
style={sendButtonContainer}
128129
>

package/src/components/MessageList/MessageFlashList.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
ViewToken,
99
} from 'react-native';
1010

11-
import Animated, { LinearTransition } from 'react-native-reanimated';
11+
import Animated from 'react-native-reanimated';
1212

1313
import type { FlashListProps, FlashListRef } from '@shopify/flash-list';
1414
import type { Channel, Event, LocalMessage, MessageResponse } from 'stream-chat';
@@ -56,6 +56,7 @@ import { useStableCallback, useStateStore } from '../../hooks';
5656
import { bumpOverlayLayoutRevision } from '../../state-store';
5757
import { MessageInputHeightState } from '../../state-store/message-input-height-store';
5858
import { primitives } from '../../theme';
59+
import { transitions } from '../../utils/transitions';
5960
import { MessageWrapper } from '../Message/MessageItemView/MessageWrapper';
6061

6162
type FlashListContextApi = { getRef?: () => FlashListRef<LocalMessage> | null } | undefined;
@@ -1094,7 +1095,7 @@ const MessageFlashListWithContext = (props: MessageFlashListPropsWithContext) =>
10941095
) : null}
10951096
</View>
10961097
<Animated.View
1097-
layout={LinearTransition.duration(200)}
1098+
layout={transitions.layout200}
10981099
style={[
10991100
styles.scrollToBottomButtonContainer,
11001101
{

package/src/components/MessageList/MessageList.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
ViewToken,
1212
} from 'react-native';
1313

14-
import Animated, { LinearTransition } from 'react-native-reanimated';
14+
import Animated from 'react-native-reanimated';
1515

1616
import debounce from 'lodash/debounce';
1717

@@ -68,6 +68,7 @@ import { useStateStore } from '../../hooks/useStateStore';
6868
import { bumpOverlayLayoutRevision } from '../../state-store';
6969
import { MessageInputHeightState } from '../../state-store/message-input-height-store';
7070
import { primitives } from '../../theme';
71+
import { transitions } from '../../utils/transitions';
7172
import { MessageWrapper } from '../Message/MessageItemView/MessageWrapper';
7273

7374
// This is just to make sure that the scrolling happens in a different task queue.
@@ -1263,7 +1264,7 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => {
12631264
<MessageListItemProvider value={messageListItemContextValue}>
12641265
<ListComponent
12651266
// TODO: Consider hiding this behind a feature flag.
1266-
layout={LayoutTransition}
1267+
layout={transitions.layout200}
12671268
contentContainerStyle={flatListContentContainerStyle}
12681269
/** Disables the MessageList UI. Which means, message actions, reactions won't work. */
12691270
data={processedMessageListWithNeighbors}
@@ -1310,7 +1311,7 @@ const MessageListWithContext = (props: MessageListPropsWithContext) => {
13101311
</View>
13111312
{scrollToBottomButtonVisible ? (
13121313
<Animated.View
1313-
layout={LinearTransition.duration(200)}
1314+
layout={transitions.layout200}
13141315
style={[
13151316
{
13161317
bottom: messageInputFloating
@@ -1462,5 +1463,3 @@ export const MessageList = (props: MessageListProps) => {
14621463
const AnimatedList = React.memo(
14631464
Animated.createAnimatedComponent(FlatList<MessageListItemWithNeighbours>),
14641465
);
1465-
1466-
const LayoutTransition = LinearTransition.duration(200);

package/src/state-store/message-overlay-store.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,7 @@ export const closeOverlay = () => {
9494
return;
9595
}
9696

97-
requestAnimationFrame(() => {
98-
if (!overlayStore.getLatestValue().id) {
99-
return;
100-
}
101-
102-
overlayStore.partialNext({ closing: true });
103-
});
97+
overlayStore.partialNext({ closing: true });
10498
};
10599

106100
let actionQueue: Array<() => void | Promise<void>> = [];

package/src/utils/transitions.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { FadeIn, FadeOut, LinearTransition, ZoomIn, ZoomOut } from 'react-native-reanimated';
2+
3+
export const transitions = {
4+
fadeIn200: FadeIn.duration(200),
5+
fadeOut200: FadeOut.duration(200),
6+
layout200: LinearTransition.duration(200),
7+
zoomIn200: ZoomIn.duration(200),
8+
zoomOut200: ZoomOut.duration(200),
9+
} as const;

0 commit comments

Comments
 (0)