Skip to content

Commit 53739b8

Browse files
authored
perf: prevent unmounting MessageBubble when STR happens (#3281)
## 🎯 Goal This PR provides a performance improvement for the swipe-to-reply functionality, where we keep: - Keeps scrolling performance the same (animated views do not pollute the virtual DOM) - Renders only one `Animated.View` (conditionally) - Animates through pushing out the rest of the content rather than displaying old content ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android
1 parent e216f85 commit 53739b8

File tree

2 files changed

+42
-41
lines changed

2 files changed

+42
-41
lines changed

package/src/components/Message/MessageSimple/MessageBubble.tsx

Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import React, { useMemo, useState } from 'react';
1+
import React, { SetStateAction, useMemo, useState } from 'react';
22
import { StyleSheet, View } from 'react-native';
33
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
44

55
import Animated, {
6-
Extrapolation,
76
interpolate,
87
runOnJS,
98
useAnimatedStyle,
@@ -17,6 +16,7 @@ import { ReactionListTopProps } from './ReactionList/ReactionListTop';
1716

1817
import { MessagesContextValue, useTheme } from '../../../contexts';
1918

19+
import { useStableCallback } from '../../../hooks';
2020
import { NativeHandlers } from '../../../native';
2121

2222
export type MessageBubbleProps = Pick<
@@ -105,6 +105,14 @@ export const SwipableMessageBubble = React.memo(
105105

106106
const triggerHaptic = NativeHandlers.triggerHaptic;
107107

108+
const setMessageContentWidth = useStableCallback((valueOrCallback: SetStateAction<number>) => {
109+
if (typeof valueOrCallback === 'number') {
110+
props.setMessageContentWidth(Math.ceil(valueOrCallback));
111+
return;
112+
}
113+
props.setMessageContentWidth(valueOrCallback);
114+
});
115+
108116
const swipeGesture = useMemo(
109117
() =>
110118
Gesture.Pan()
@@ -167,61 +175,48 @@ export const SwipableMessageBubble = React.memo(
167175
);
168176
}),
169177
[
170-
isSwiping,
171178
messageSwipeToReplyHitSlop,
172-
onSwipe,
173179
touchStart,
180+
isSwiping,
181+
shouldRenderSwipeableWrapper,
174182
translateX,
183+
onSwipe,
175184
triggerHaptic,
176-
shouldRenderSwipeableWrapper,
177185
],
178186
);
179187

180-
const messageBubbleAnimatedStyle = useAnimatedStyle(
181-
() => ({
182-
transform: [{ translateX: translateX.value }],
183-
}),
184-
[],
185-
);
186-
187188
const swipeContentAnimatedStyle = useAnimatedStyle(
188189
() => ({
189190
opacity: interpolate(translateX.value, [0, SWIPABLE_THRESHOLD], [0, 1]),
190-
transform: [
191-
{
192-
translateX: interpolate(
193-
translateX.value,
194-
[0, SWIPABLE_THRESHOLD],
195-
[-SWIPABLE_THRESHOLD, 0],
196-
Extrapolation.CLAMP,
197-
),
198-
},
199-
],
191+
width: translateX.value,
200192
}),
201193
[],
202194
);
203195

204196
return (
205197
<GestureDetector gesture={swipeGesture}>
206-
<View hitSlop={messageSwipeToReplyHitSlop} style={[styles.contentWrapper, contentWrapper]}>
198+
<View
199+
hitSlop={messageSwipeToReplyHitSlop}
200+
style={[
201+
styles.contentWrapper,
202+
contentWrapper,
203+
props.messageContentWidth > 0 && shouldRenderAnimatedWrapper
204+
? { width: props.messageContentWidth }
205+
: {},
206+
]}
207+
>
207208
{shouldRenderAnimatedWrapper ? (
208-
<>
209-
<AnimatedWrapper
210-
style={[
211-
styles.swipeContentContainer,
212-
swipeContentAnimatedStyle,
213-
swipeContentContainer,
214-
]}
215-
>
216-
{MessageSwipeContent ? <MessageSwipeContent /> : null}
217-
</AnimatedWrapper>
218-
<AnimatedWrapper pointerEvents='box-none' style={messageBubbleAnimatedStyle}>
219-
<MessageBubble {...messageBubbleProps} />
220-
</AnimatedWrapper>
221-
</>
222-
) : (
223-
<MessageBubble {...messageBubbleProps} />
224-
)}
209+
<AnimatedWrapper
210+
style={[
211+
styles.swipeContentContainer,
212+
swipeContentAnimatedStyle,
213+
swipeContentContainer,
214+
]}
215+
>
216+
{MessageSwipeContent ? <MessageSwipeContent /> : null}
217+
</AnimatedWrapper>
218+
) : null}
219+
<MessageBubble {...messageBubbleProps} setMessageContentWidth={setMessageContentWidth} />
225220
</View>
226221
</GestureDetector>
227222
);
@@ -234,6 +229,8 @@ const styles = StyleSheet.create({
234229
flexDirection: 'row',
235230
},
236231
swipeContentContainer: {
237-
position: 'absolute',
232+
flexShrink: 0,
233+
overflow: 'hidden',
234+
position: 'relative',
238235
},
239236
});

package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ exports[`Thread should match thread snapshot 1`] = `
380380
"flexDirection": "row",
381381
},
382382
{},
383+
{},
383384
]
384385
}
385386
>
@@ -749,6 +750,7 @@ exports[`Thread should match thread snapshot 1`] = `
749750
"flexDirection": "row",
750751
},
751752
{},
753+
{},
752754
]
753755
}
754756
>
@@ -1156,6 +1158,7 @@ exports[`Thread should match thread snapshot 1`] = `
11561158
"flexDirection": "row",
11571159
},
11581160
{},
1161+
{},
11591162
]
11601163
}
11611164
>
@@ -1529,6 +1532,7 @@ exports[`Thread should match thread snapshot 1`] = `
15291532
"flexDirection": "row",
15301533
},
15311534
{},
1535+
{},
15321536
]
15331537
}
15341538
>

0 commit comments

Comments
 (0)