Skip to content

Commit e13bcb6

Browse files
authored
Fix/ ColorPalette scrolling and extra renders (#2179)
* fix extra renders + fix scrolling to selected chip * fix scrolling * move setTimeout to scrollToSelected and add a note
1 parent 6b7b239 commit e13bcb6

File tree

1 file changed

+41
-45
lines changed

1 file changed

+41
-45
lines changed

src/components/colorPalette/index.tsx

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import _ from 'lodash';
22
import memoize from 'memoize-one';
33
import React, {PureComponent} from 'react';
4-
import {StyleSheet, UIManager, findNodeHandle, StyleProp, ViewStyle} from 'react-native';
4+
import {StyleSheet, StyleProp, ViewStyle} from 'react-native';
55
import {Colors} from '../../style';
66
import {Constants} from '../../commons/new';
77
import View from '../view';
88
import Carousel from '../carousel';
99
import ScrollBar from '../scrollBar';
1010
import PageControl from '../pageControl';
11-
import ColorSwatch, {SWATCH_SIZE} from '../colorSwatch';
12-
11+
import ColorSwatch, {SWATCH_SIZE, SWATCH_MARGIN} from '../colorSwatch';
1312

1413
interface Props {
1514
/**
@@ -58,10 +57,10 @@ interface Props {
5857
export type ColorPaletteProps = Props;
5958

6059
interface State {
61-
currentPage: number,
62-
scrollable: boolean,
63-
orientation?: string,
64-
contentWidth?: number
60+
currentPage: number;
61+
scrollable: boolean;
62+
orientation?: string;
63+
contentWidth?: number;
6564
}
6665

6766
const VERTICAL_PADDING = 16;
@@ -100,7 +99,7 @@ class ColorPalette extends PureComponent<Props, State> {
10099

101100
carousel: React.RefObject<typeof Carousel> = React.createRef();
102101
scrollBar: React.RefObject<any> = React.createRef();
103-
itemsRefs?: React.RefObject<typeof ColorSwatch>[] = undefined;
102+
itemsRefs?: any = React.createRef();
104103
selectedColorIndex?: number = undefined;
105104
selectedPage?: number = undefined;
106105
currentColorsCount?: number = undefined;
@@ -113,6 +112,18 @@ class ColorPalette extends PureComponent<Props, State> {
113112

114113
componentDidMount() {
115114
this.dimensionsChangeListener = Constants.addDimensionsEventListener(this.onOrientationChanged);
115+
_.times(this.props.colors.length, i => {
116+
this.itemsRefs.current[i] = React.createRef();
117+
});
118+
this.scrollToSelected();
119+
}
120+
121+
componentDidUpdate(prevProps: Props) {
122+
if (this.props.colors !== prevProps.colors) {
123+
const newIndex = this.itemsRefs.current.length;
124+
this.itemsRefs.current[newIndex] = React.createRef();
125+
this.scrollToSelected();
126+
}
116127
}
117128

118129
componentWillUnmount() {
@@ -127,7 +138,7 @@ class ColorPalette extends PureComponent<Props, State> {
127138
};
128139

129140
initLocalVariables() {
130-
this.itemsRefs = undefined;
141+
this.itemsRefs.current = [];
131142
this.selectedColorIndex = undefined;
132143
this.selectedPage = undefined;
133144
this.currentColorsCount = this.colors.length;
@@ -208,38 +219,36 @@ class ColorPalette extends PureComponent<Props, State> {
208219
return (margin - 0.001) / 2;
209220
}
210221

211-
scrollToSelected() {
222+
scrollToSelected = () => setTimeout(() => {
212223
const {scrollable, currentPage} = this.state;
213224

214-
if (scrollable && this.selectedColorIndex !== undefined && this.itemsRefs) {
215-
const childRef = this.itemsRefs[this.selectedColorIndex];
225+
if (scrollable && this.selectedColorIndex !== undefined && this.itemsRefs.current) {
226+
// The this.selectedColorIndex layout doesn't update on time
227+
// so we use this.selectedColorIndex - 1 and add an offset of 1 Swatch
228+
const childRef: any = this.itemsRefs.current[this.selectedColorIndex - 1]?.current;
216229

217230
if (childRef) {
218-
const handle = findNodeHandle(childRef.current);
219-
if (handle) {
220-
//@ts-ignore
221-
UIManager.measureLayoutRelativeToParent(handle, e => {
222-
console.warn(e);
223-
},
224-
(x: number, _y: number, w: number, _h: number) => {
225-
if (x + w > this.containerWidth) {
226-
this.scrollBar?.current?.scrollTo({
227-
x: x + w + HORIZONTAL_PADDING - this.containerWidth,
228-
y: 0,
229-
animated: false
230-
});
231-
}
231+
const childLayout = childRef.getLayout();
232+
const leftMargins = this.getHorizontalMargins(this.selectedColorIndex).marginLeft;
233+
const childX = childLayout.x + childLayout.width + SWATCH_MARGIN + leftMargins + SWATCH_SIZE;
234+
if (childX > this.containerWidth) {
235+
this.scrollBar?.current?.scrollTo({
236+
x: childX + HORIZONTAL_PADDING - this.containerWidth,
237+
y: 0,
238+
animated: false
232239
});
233240
}
241+
} else if (this.usePagination) {
242+
this.carousel?.current?.goToPage(this.selectedPage || currentPage, false);
234243
}
235-
} else if (this.usePagination) {
236-
this.carousel?.current?.goToPage(this.selectedPage || currentPage, false);
237244
}
238-
}
245+
}, 100)
239246

240247
onContentSizeChange = (contentWidth: number) => {
241248
this.setState({
242-
scrollable: contentWidth > this.containerWidth, contentWidth});
249+
scrollable: contentWidth > this.containerWidth,
250+
contentWidth
251+
});
243252
};
244253

245254
onChangePage = (index: number) => {
@@ -250,12 +259,6 @@ class ColorPalette extends PureComponent<Props, State> {
250259
this.props.onValueChange?.(value, options);
251260
};
252261

253-
onLayout = () => {
254-
setTimeout(() => {
255-
this.scrollToSelected();
256-
}, 0);
257-
};
258-
259262
getHorizontalMargins = (index: number) => {
260263
const isFirst = index === 0;
261264
const isOnLeft = isFirst || index % this.itemsPerRow === 0;
@@ -292,12 +295,6 @@ class ColorPalette extends PureComponent<Props, State> {
292295
}
293296
};
294297

295-
addRefByIndex = (index: number, ref?: any) => {
296-
if (this.itemsRefs && ref) {
297-
this.itemsRefs[index] = ref;
298-
}
299-
}
300-
301298
renderColorSwatch(color: string, index: number) {
302299
const {animatedIndex, testID} = this.props;
303300

@@ -311,18 +308,17 @@ class ColorPalette extends PureComponent<Props, State> {
311308
selected={this.value === color}
312309
animated={index === animatedIndex}
313310
onPress={this.onValueChange}
314-
ref={r => this.addRefByIndex(index, r)}
311+
ref={this.itemsRefs.current[index]}
315312
testID={`${testID}-${color}`}
316313
/>
317314
);
318315
}
319316

320317
renderPalette(props: Props, contentStyle: StyleProp<ViewStyle>, colors: string[], pageIndex: number) {
321318
const {style, ...others} = props;
322-
this.itemsRefs = [];
323319

324320
return (
325-
<View key={pageIndex} {...others} style={[styles.paletteContainer, contentStyle, style]} onLayout={this.onLayout}>
321+
<View key={pageIndex} {...others} style={[styles.paletteContainer, contentStyle, style]}>
326322
{_.map(colors, (color, i) => {
327323
if (color === this.value) {
328324
this.selectedColorIndex = i;

0 commit comments

Comments
 (0)