Skip to content

Commit

Permalink
fix: sync scroll position on dynamic tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
andreialecu committed Feb 5, 2021
1 parent ec513cd commit 4c9cfce
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 10 deletions.
3 changes: 2 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"react-native-gesture-handler": "^1.9.0",
"react-native-reanimated": "2.0.0-rc.0",
"react-native-web": "~0.13.12",
"use-debounce": "^5.2.0"
"use-debounce": "^5.2.0",
"use-deep-compare": "^1.1.0"
},
"devDependencies": {
"@babel/core": "~7.9.0",
Expand Down
12 changes: 12 additions & 0 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2715,6 +2715,11 @@ depd@~1.1.2:
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=

dequal@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dequal/-/dequal-1.0.0.tgz#41c6065e70de738541c82cdbedea5292277a017e"
integrity sha512-/Nd1EQbQbI9UbSHrMiKZjFLrXSnU328iQdZKPQf78XQI6C+gutkFUeoHpG5J08Ioa6HeRbRNFpSIclh1xyG0mw==

destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
Expand Down Expand Up @@ -6286,6 +6291,13 @@ use-debounce@^5.2.0:
resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-5.2.0.tgz#3cb63f5c46f40092c570356e441dbc016ffb2f8b"
integrity sha512-lW4tbPsTnvPKYqOYXp5xZ7SP7No/ARLqqQqoyRKuSzP0HxR9arhSAhznXUZFoNPWDRij8fog+N6sYbjb8c3kzw==

use-deep-compare@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/use-deep-compare/-/use-deep-compare-1.1.0.tgz#85580dde751f68400bf6ef7e043c7f986595cef8"
integrity sha512-6yY3zmKNCJ1jjIivfZMZMReZjr8e6iC6Uqtp701jvWJ6ejC/usXD+JjmslZDPJQgX8P4B1Oi5XSLHkOLeYSJsA==
dependencies:
dequal "1.0.0"

use-subscription@^1.0.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,7 @@
"typescript"
]
},
"dependencies": {}
"dependencies": {
"use-deep-compare": "^1.1.0"
}
}
33 changes: 29 additions & 4 deletions src/createCollapsibleTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,7 @@ const createCollapsibleTabs = <T extends TabName>() => {
) => {
const containerRef = useContainerRef()

const tabProps = useTabProps(children, Tab)
const tabNamesArray = React.useMemo(() => [...tabProps.keys()], [
tabProps,
])
const [tabProps, tabNamesArray] = useTabProps(children, Tab)

const [refMap, setRef] = useAnimatedDynamicRefs()

Expand Down Expand Up @@ -277,6 +274,15 @@ const createCollapsibleTabs = <T extends TabName>() => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [windowWidth])

const afterRender = useSharedValue(0)
React.useEffect(() => {
if (!firstRender.current) pagerOpacity.value = 0
afterRender.value = withDelay(
ONE_FRAME_MS * 5,
withTiming(1, { duration: 0 })
)
}, [afterRender, pagerOpacity, tabNamesArray])

React.useEffect(() => {
if (firstRender.current) {
if (initialTabName !== undefined && index.value !== 0) {
Expand All @@ -290,6 +296,25 @@ const createCollapsibleTabs = <T extends TabName>() => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [containerRef, initialTabName, windowWidth])

// the purpose of this is to scroll to the proper position if dynamic tabs are changing
useAnimatedReaction(
() => {
return afterRender.value === 1
},
(trigger) => {
if (trigger) {
afterRender.value = 0
tabNamesArray.forEach((name) => {
'worklet'
scrollToImpl(refMap[name], 0, scrollY.value[index.value], false)
})

pagerOpacity.value = withTiming(1)
}
},
[tabNamesArray, refMap, afterRender]
)

// derived from scrollX
// calculate the next offset and index if swiping
// if scrollX changes from tab press,
Expand Down
17 changes: 14 additions & 3 deletions src/hooks.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMemo, Children, useState, useCallback } from 'react'
import { ContainerRef, RefComponent } from 'react-native-collapsible-tab-view'
import { useAnimatedRef } from 'react-native-reanimated'
import { useDeepCompareMemo } from 'use-deep-compare'

import { Ref, TabName, TabReactElement, TabsWithProps } from './types'

Expand Down Expand Up @@ -32,15 +33,16 @@ export function useAnimatedDynamicRefs(): [
export function useTabProps<T extends TabName>(
children: TabReactElement<T>[] | TabReactElement<T>,
tabType: Function
) {
): [TabsWithProps<T>, T[]] {
const options = useMemo(() => {
const tabOptions: TabsWithProps<T> = new Map()
Children.forEach(children, (element, index) => {
if (element.type !== tabType)
throw new Error(
'Container children must be wrapped in a <Tabs.Tab ... /> component'
)
const { name, ...options } = element.props
// make sure children is excluded otherwise our props will mutate too much
const { name, children, ...options } = element.props
tabOptions.set(name, {
index,
name,
Expand All @@ -49,5 +51,14 @@ export function useTabProps<T extends TabName>(
})
return tabOptions
}, [children, tabType])
return options
const optionEntries = [...options.entries()]
const optionKeys = [...options.keys()]

const memoizedOptions = useDeepCompareMemo(() => options, [optionEntries])

const memoizedTabNames = useDeepCompareMemo(() => [...options.keys()], [
optionKeys,
])

return [memoizedOptions, memoizedTabNames]
}
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,5 @@ export type CollapsibleStyle = {

export type TabsWithProps<T extends TabName> = Map<
T,
TabProps<T> & { index: number }
Omit<TabProps<T>, 'children'> & { index: number }
>
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4251,6 +4251,11 @@ deprecation@^2.0.0, deprecation@^2.3.1:
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==

dequal@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dequal/-/dequal-1.0.0.tgz#41c6065e70de738541c82cdbedea5292277a017e"
integrity sha512-/Nd1EQbQbI9UbSHrMiKZjFLrXSnU328iQdZKPQf78XQI6C+gutkFUeoHpG5J08Ioa6HeRbRNFpSIclh1xyG0mw==

destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
Expand Down Expand Up @@ -10350,6 +10355,13 @@ url-parse-lax@^3.0.0:
dependencies:
prepend-http "^2.0.0"

use-deep-compare@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/use-deep-compare/-/use-deep-compare-1.1.0.tgz#85580dde751f68400bf6ef7e043c7f986595cef8"
integrity sha512-6yY3zmKNCJ1jjIivfZMZMReZjr8e6iC6Uqtp701jvWJ6ejC/usXD+JjmslZDPJQgX8P4B1Oi5XSLHkOLeYSJsA==
dependencies:
dequal "1.0.0"

use-subscription@^1.0.0:
version "1.5.1"
resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1"
Expand Down

0 comments on commit 4c9cfce

Please sign in to comment.