simplify how x position is calculated for scrollTo in TabBar (#820)

This commit is contained in:
Ansh 2023-06-01 08:19:15 -07:00 committed by GitHub
parent 31a41d9b09
commit 8fde55b59b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,12 +1,5 @@
import React, { import React, {useRef, useMemo, useEffect, useState, useCallback} from 'react'
useRef, import {StyleSheet, View, ScrollView, LayoutChangeEvent} from 'react-native'
createRef,
useMemo,
useEffect,
useState,
useCallback,
} from 'react'
import {StyleSheet, View, ScrollView} from 'react-native'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {PressableWithHover} from '../util/PressableWithHover' import {PressableWithHover} from '../util/PressableWithHover'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@ -33,17 +26,16 @@ export function TabBar({
const pal = usePalette('default') const pal = usePalette('default')
const scrollElRef = useRef<ScrollView>(null) const scrollElRef = useRef<ScrollView>(null)
const [itemXs, setItemXs] = useState<number[]>([]) const [itemXs, setItemXs] = useState<number[]>([])
const itemRefs = useMemo(
() => Array.from({length: items.length}).map(() => createRef<View>()),
[items.length],
)
const indicatorStyle = useMemo( const indicatorStyle = useMemo(
() => ({borderBottomColor: indicatorColor || pal.colors.link}), () => ({borderBottomColor: indicatorColor || pal.colors.link}),
[indicatorColor, pal], [indicatorColor, pal],
) )
// scrolls to the selected item when the page changes
useEffect(() => { useEffect(() => {
scrollElRef.current?.scrollTo({x: itemXs[selectedPage] || 0}) scrollElRef.current?.scrollTo({
x: itemXs[selectedPage] || 0,
})
}, [scrollElRef, itemXs, selectedPage]) }, [scrollElRef, itemXs, selectedPage])
const onPressItem = useCallback( const onPressItem = useCallback(
@ -53,26 +45,21 @@ export function TabBar({
onPressSelected?.() onPressSelected?.()
} }
}, },
[onSelect, onPressSelected, selectedPage], [onSelect, selectedPage, onPressSelected],
) )
const onLayout = React.useCallback(() => { // calculates the x position of each item on mount and on layout change
const promises = [] const onItemLayout = React.useCallback(
for (let i = 0; i < items.length; i++) { (e: LayoutChangeEvent, index: number) => {
promises.push( const x = e.nativeEvent.layout.x
new Promise<number>(resolve => { setItemXs(prev => {
if (!itemRefs[i].current) { const Xs = [...prev]
return resolve(0) Xs[index] = x
} return Xs
})
itemRefs[i].current?.measure((x: number) => resolve(x)) },
}), [],
) )
}
Promise.all(promises).then((Xs: number[]) => {
setItemXs(Xs)
})
}, [itemRefs, setItemXs, items.length])
return ( return (
<View testID={testID} style={[pal.view, styles.outer]}> <View testID={testID} style={[pal.view, styles.outer]}>
@ -80,14 +67,13 @@ export function TabBar({
horizontal={true} horizontal={true}
showsHorizontalScrollIndicator={false} showsHorizontalScrollIndicator={false}
ref={scrollElRef} ref={scrollElRef}
contentContainerStyle={styles.contentContainer} contentContainerStyle={styles.contentContainer}>
onLayout={onLayout}>
{items.map((item, i) => { {items.map((item, i) => {
const selected = i === selectedPage const selected = i === selectedPage
return ( return (
<PressableWithHover <PressableWithHover
ref={itemRefs[i]}
key={item} key={item}
onLayout={e => onItemLayout(e, i)}
style={[styles.item, selected && indicatorStyle]} style={[styles.item, selected && indicatorStyle]}
hoverStyle={pal.viewLight} hoverStyle={pal.viewLight}
onPress={() => onPressItem(i)}> onPress={() => onPressItem(i)}>