Skip to content

Commit

Permalink
fix: lazy FlashList scroll sync issue
Browse files Browse the repository at this point in the history
  • Loading branch information
andreialecu committed Apr 3, 2024
1 parent 6d28128 commit 1b89ec7
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 23 deletions.
2 changes: 1 addition & 1 deletion example/src/Shared/ExampleComponentFlashList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type Props = {
const Example = React.forwardRef<CollapsibleRef, Props>(
({ emptyContacts, ...props }, ref) => {
return (
<Tabs.Container ref={ref} headerHeight={HEADER_HEIGHT} {...props}>
<Tabs.Container ref={ref} headerHeight={HEADER_HEIGHT} lazy {...props}>
{props.hideArticleTab ? (
<Tabs.Tab name="article" label="Article">
<Article />
Expand Down
2 changes: 1 addition & 1 deletion example/src/Shared/ExampleComponentMasonryFlashList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type Props = {
const Example = React.forwardRef<CollapsibleRef, Props>(
({ emptyContacts, ...props }, ref) => {
return (
<Tabs.Container ref={ref} headerHeight={HEADER_HEIGHT} {...props}>
<Tabs.Container ref={ref} headerHeight={HEADER_HEIGHT} lazy {...props}>
{props.hideArticleTab ? (
<Tabs.Tab name="article" label="Article">
<Article />
Expand Down
30 changes: 21 additions & 9 deletions src/FlashList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import type {
FlashList as SPFlashList,
} from '@shopify/flash-list'
import React, { useCallback } from 'react'
import Animated from 'react-native-reanimated'
import Animated, {
useSharedValue,
useAnimatedReaction,
} from 'react-native-reanimated'

import {
useAfterMountEffect,
useChainCallback,
useCollapsibleStyle,
useConvertAnimatedToValue,
Expand Down Expand Up @@ -72,12 +74,22 @@ function FlashListImpl<R>(

const { scrollHandler, enable } = useScrollHandlerY(name)

const onLayout = useAfterMountEffect(rest.onLayout, () => {
'worklet'
// we enable the scroll event after mounting
// otherwise we get an `onScroll` call with the initial scroll position which can break things
enable(true)
})
const hadLoad = useSharedValue(false)

const onLoad = useCallback(() => {
hadLoad.value = true
}, [hadLoad])

useAnimatedReaction(
() => {
return hadLoad.value
},
(ready) => {
if (ready) {
enable(true)
}
}
)

const { progressViewOffset, contentContainerStyle } = useCollapsibleStyle()

Expand Down Expand Up @@ -141,7 +153,7 @@ function FlashListImpl<R>(
// @ts-expect-error typescript complains about `unknown` in the memo, it should be T
<FlashListMemo
{...rest}
onLayout={onLayout}
onLoad={onLoad}
ref={refWorkaround}
contentContainerStyle={memoContentContainerStyle}
bouncesZoom={false}
Expand Down
30 changes: 21 additions & 9 deletions src/MasonryFlashList.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { MasonryFlashListProps, MasonryFlashListRef } from '@shopify/flash-list'
import React, { useCallback } from 'react'
import Animated from 'react-native-reanimated'
import Animated, {
useAnimatedReaction,
useSharedValue,
} from 'react-native-reanimated'

import {
useAfterMountEffect,
useChainCallback,
useCollapsibleStyle,
useConvertAnimatedToValue,
Expand Down Expand Up @@ -76,12 +78,22 @@ function MasonryFlashListImpl<R>(

const { scrollHandler, enable } = useScrollHandlerY(name)

const onLayout = useAfterMountEffect(rest.onLayout, () => {
'worklet'
// we enable the scroll event after mounting
// otherwise we get an `onScroll` call with the initial scroll position which can break things
enable(true)
})
const hadLoad = useSharedValue(false)

const onLoad = useCallback(() => {
hadLoad.value = true
}, [hadLoad])

useAnimatedReaction(
() => {
return hadLoad.value
},
(ready) => {
if (ready) {
enable(true)
}
}
)

const { progressViewOffset, contentContainerStyle } = useCollapsibleStyle()

Expand Down Expand Up @@ -145,7 +157,7 @@ function MasonryFlashListImpl<R>(
// @ts-expect-error typescript complains about `unknown` in the memo, it should be T
<MasonryFlashListMemo
{...rest}
onLayout={onLayout}
onLoad={onLoad}
contentContainerStyle={memoContentContainerStyle}
ref={refWorkaround}
bouncesZoom={false}
Expand Down
19 changes: 16 additions & 3 deletions src/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,27 @@ export const useScrollHandlerY = (name: TabName) => {

const enabled = useSharedValue(false)

const scrollTo = useScroller()

const enable = useCallback(
(toggle: boolean) => {
'worklet'
enabled.value = toggle

if (toggle) {
const tabIndex = tabNames.value.findIndex((n) => n === name)

const ref = refMap[name]
scrollTo(
ref,
0,
scrollY.value[tabIndex],
false,
`[${name}] restore scroll position - enable`
)
}
},
[enabled]
[enabled, name, refMap, scrollTo, scrollY.value, tabNames.value]
)

/**
Expand All @@ -293,8 +308,6 @@ export const useScrollHandlerY = (name: TabName) => {
name,
])

const scrollTo = useScroller()

const scrollAnimation = useSharedValue<number | undefined>(undefined)

useAnimatedReaction(
Expand Down

0 comments on commit 1b89ec7

Please sign in to comment.