Skip to content

Commit

Permalink
Fix/segmentedControl performance (#1375)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
lidord-wix authored Jul 27, 2021
1 parent 7b3a43c commit b5068ab
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 24 deletions.
17 changes: 7 additions & 10 deletions demo/src/screens/componentScreens/SegmentedControlScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {useCallback} from 'react';
import {StyleSheet} from 'react-native';
import {Text, View, Colors, SegmentedControl, Assets, Spacings, BorderRadiuses} from 'react-native-ui-lib';

Expand All @@ -20,29 +20,28 @@ const segments = {
};

const SegmentedControlScreen = () => {
const onChangeIndex = (segment: string, index: number) => {
console.warn('Index ' + index + ' of the ' + segment + ' segmentedControl was pressed');
};

const onChangeIndex = useCallback((index: number) => {
console.warn('Index ' + index + ' of the second segmentedControl was pressed');
}, []);

return (
<View flex bottom padding-page>
<View flex centerV>
<View center>
<SegmentedControl onChangeIndex={(index: number) => onChangeIndex('first', index)} segments={segments.first}/>
<SegmentedControl segments={segments.first}/>
<SegmentedControl
onChangeIndex={(index: number) => onChangeIndex('second', index)}
onChangeIndex={onChangeIndex}
containerStyle={styles.container}
segments={segments.second}
initialIndex={2}
/>
<SegmentedControl
onChangeIndex={(index: number) => onChangeIndex('third', index)}
containerStyle={styles.container}
activeColor={Colors.red30}
segments={segments.third}
/>
<SegmentedControl
onChangeIndex={(index: number) => onChangeIndex('forth', index)}
containerStyle={styles.container}
segments={segments.forth}
activeColor={Colors.grey10}
Expand All @@ -54,12 +53,10 @@ const SegmentedControlScreen = () => {
</View>
<SegmentedControl
containerStyle={styles.container}
onChangeIndex={(index: number) => onChangeIndex('second', index)}
segments={segments.fifth}
/>
<SegmentedControl
containerStyle={styles.container}
onChangeIndex={(index: number) => onChangeIndex('second', index)}
segments={segments.sixth}
/>
</View>
Expand Down
32 changes: 18 additions & 14 deletions src/components/segmentedControl/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,26 +90,30 @@ const SegmentedControl = (props: SegmentedControlProps) => {

const segmentsStyle = useRef([] as {x: number; width: number}[]);
const segmentedControlHeight = useRef(0);
const indexRef = useRef(0);
const segmentsCounter = useRef(0);
const animatedValue = useRef(new Reanimated.Value(initialIndex));

const updateSelectedSegment = useCallback((index: number) => {
Reanimated.timing(animatedValue.current, {
toValue: index,
duration: 300,
easing: Easing.bezier(0.33, 1, 0.68, 1)
}).start();

return setSelectedSegment(index);
}, []);
const changeIndex = useCallback(_.throttle(() => {
onChangeIndex?.(indexRef.current);
},
400,
{trailing: true, leading: false}),
[]);

const onSegmentPress = useCallback((index: number) => {
if (selectedSegment !== index) {
onChangeIndex?.(index);
updateSelectedSegment(index);
setSelectedSegment(index);
indexRef.current = index;

Reanimated.timing(animatedValue.current, {
toValue: index,
duration: 300,
easing: Easing.bezier(0.33, 1, 0.68, 1)
}).start(changeIndex);
}
},
[onChangeIndex, selectedSegment, updateSelectedSegment]);
[onChangeIndex, selectedSegment]);

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

const width = interpolate(animatedValue.current, {
inputRange: _.times(segmentsCounter.current),
outputRange: _.map(segmentsStyle.current, segment => segment.width)
outputRange: _.map(segmentsStyle.current, segment => segment.width - 2 * BORDER_WIDTH)
});

return {width, left};
Expand Down

0 comments on commit b5068ab

Please sign in to comment.