Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: lazy FlashList scroll sync issue #393

Merged
merged 1 commit into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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