Skip to content

Commit b5068ab

Browse files
authored
Fix/segmentedControl performance (#1375)
* remove selectedSegment from dependencies * fix screen * performance fixes * remove warning * pass segment onPress only if needed * fix alignment * add setTimeout to onChangeIndex * make onPress required * Add throttle
1 parent 7b3a43c commit b5068ab

File tree

2 files changed

+25
-24
lines changed

2 files changed

+25
-24
lines changed

demo/src/screens/componentScreens/SegmentedControlScreen.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, {useCallback} from 'react';
22
import {StyleSheet} from 'react-native';
33
import {Text, View, Colors, SegmentedControl, Assets, Spacings, BorderRadiuses} from 'react-native-ui-lib';
44

@@ -20,29 +20,28 @@ const segments = {
2020
};
2121

2222
const SegmentedControlScreen = () => {
23-
const onChangeIndex = (segment: string, index: number) => {
24-
console.warn('Index ' + index + ' of the ' + segment + ' segmentedControl was pressed');
25-
};
23+
24+
const onChangeIndex = useCallback((index: number) => {
25+
console.warn('Index ' + index + ' of the second segmentedControl was pressed');
26+
}, []);
2627

2728
return (
2829
<View flex bottom padding-page>
2930
<View flex centerV>
3031
<View center>
31-
<SegmentedControl onChangeIndex={(index: number) => onChangeIndex('first', index)} segments={segments.first}/>
32+
<SegmentedControl segments={segments.first}/>
3233
<SegmentedControl
33-
onChangeIndex={(index: number) => onChangeIndex('second', index)}
34+
onChangeIndex={onChangeIndex}
3435
containerStyle={styles.container}
3536
segments={segments.second}
3637
initialIndex={2}
3738
/>
3839
<SegmentedControl
39-
onChangeIndex={(index: number) => onChangeIndex('third', index)}
4040
containerStyle={styles.container}
4141
activeColor={Colors.red30}
4242
segments={segments.third}
4343
/>
4444
<SegmentedControl
45-
onChangeIndex={(index: number) => onChangeIndex('forth', index)}
4645
containerStyle={styles.container}
4746
segments={segments.forth}
4847
activeColor={Colors.grey10}
@@ -54,12 +53,10 @@ const SegmentedControlScreen = () => {
5453
</View>
5554
<SegmentedControl
5655
containerStyle={styles.container}
57-
onChangeIndex={(index: number) => onChangeIndex('second', index)}
5856
segments={segments.fifth}
5957
/>
6058
<SegmentedControl
6159
containerStyle={styles.container}
62-
onChangeIndex={(index: number) => onChangeIndex('second', index)}
6360
segments={segments.sixth}
6461
/>
6562
</View>

src/components/segmentedControl/index.tsx

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,26 +90,30 @@ const SegmentedControl = (props: SegmentedControlProps) => {
9090

9191
const segmentsStyle = useRef([] as {x: number; width: number}[]);
9292
const segmentedControlHeight = useRef(0);
93+
const indexRef = useRef(0);
9394
const segmentsCounter = useRef(0);
9495
const animatedValue = useRef(new Reanimated.Value(initialIndex));
9596

96-
const updateSelectedSegment = useCallback((index: number) => {
97-
Reanimated.timing(animatedValue.current, {
98-
toValue: index,
99-
duration: 300,
100-
easing: Easing.bezier(0.33, 1, 0.68, 1)
101-
}).start();
102-
103-
return setSelectedSegment(index);
104-
}, []);
97+
const changeIndex = useCallback(_.throttle(() => {
98+
onChangeIndex?.(indexRef.current);
99+
},
100+
400,
101+
{trailing: true, leading: false}),
102+
[]);
105103

106104
const onSegmentPress = useCallback((index: number) => {
107105
if (selectedSegment !== index) {
108-
onChangeIndex?.(index);
109-
updateSelectedSegment(index);
106+
setSelectedSegment(index);
107+
indexRef.current = index;
108+
109+
Reanimated.timing(animatedValue.current, {
110+
toValue: index,
111+
duration: 300,
112+
easing: Easing.bezier(0.33, 1, 0.68, 1)
113+
}).start(changeIndex);
110114
}
111115
},
112-
[onChangeIndex, selectedSegment, updateSelectedSegment]);
116+
[onChangeIndex, selectedSegment]);
113117

114118
const onLayout = useCallback((index: number, event: LayoutChangeEvent) => {
115119
const {x, width, height} = event.nativeEvent.layout;
@@ -125,12 +129,12 @@ const SegmentedControl = (props: SegmentedControlProps) => {
125129
if (segmentsCounter.current === segments?.length) {
126130
const left = interpolate(animatedValue.current, {
127131
inputRange: _.times(segmentsCounter.current),
128-
outputRange: _.map(segmentsStyle.current, segment => segment.x - BORDER_WIDTH)
132+
outputRange: _.map(segmentsStyle.current, segment => segment.x)
129133
});
130134

131135
const width = interpolate(animatedValue.current, {
132136
inputRange: _.times(segmentsCounter.current),
133-
outputRange: _.map(segmentsStyle.current, segment => segment.width)
137+
outputRange: _.map(segmentsStyle.current, segment => segment.width - 2 * BORDER_WIDTH)
134138
});
135139

136140
return {width, left};

0 commit comments

Comments
 (0)