diff --git a/src/lib/hooks/useDedupe.ts b/src/lib/hooks/useDedupe.ts index b6ca5abbf6..45a9bf1829 100644 --- a/src/lib/hooks/useDedupe.ts +++ b/src/lib/hooks/useDedupe.ts @@ -1,9 +1,9 @@ -import React from 'react' +import {useCallback, useRef} from 'react' -export const useDedupe = (timeout = 250) => { - const canDo = React.useRef(true) +export function useDedupe(timeout = 250) { + const canDo = useRef(true) - return React.useCallback( + return useCallback( (cb: () => unknown) => { if (canDo.current) { canDo.current = false diff --git a/src/view/com/util/List.tsx b/src/view/com/util/List.tsx index 6a362cd2d7..c8c4007f02 100644 --- a/src/view/com/util/List.tsx +++ b/src/view/com/util/List.tsx @@ -1,4 +1,4 @@ -import React, {memo} from 'react' +import {forwardRef, memo, useDeferredValue, useMemo} from 'react' import {RefreshControl, type ViewToken} from 'react-native' import { type FlatListPropsWithLayout, @@ -9,6 +9,7 @@ import { import {updateActiveVideoViewAsync} from '@haileyok/bluesky-video' import {useDedupe} from '#/lib/hooks/useDedupe' +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useScrollHandlers} from '#/lib/ScrollContext' import {addStyle} from '#/lib/styles' import {useLightbox} from '#/state/lightbox' @@ -43,7 +44,7 @@ export type ListRef = React.RefObject const SCROLLED_DOWN_LIMIT = 200 -let List = React.forwardRef( +let List = forwardRef( ( { onScrolledDownChange, @@ -63,9 +64,11 @@ let List = React.forwardRef( const dedupe = useDedupe(400) const scrollsToTop = useAllowScrollToTop() - function handleScrolledDownChange(didScrollDown: boolean) { - onScrolledDownChange?.(didScrollDown) - } + const handleScrolledDownChange = useNonReactiveCallback( + (didScrollDown: boolean) => { + onScrolledDownChange?.(didScrollDown) + }, + ) // Intentionally destructured outside the main thread closure. // See https://github.com/bluesky-social/social-app/pull/4108. @@ -106,7 +109,7 @@ let List = React.forwardRef( }, }) - const [onViewableItemsChanged, viewabilityConfig] = React.useMemo(() => { + const [onViewableItemsChanged, viewabilityConfig] = useMemo(() => { if (!onItemSeen) { return [undefined, undefined] } @@ -187,5 +190,5 @@ export {List} const useAllowScrollToTop = IS_IOS ? useAllowScrollToTopIOS : () => undefined function useAllowScrollToTopIOS() { const {activeLightbox} = useLightbox() - return !activeLightbox + return useDeferredValue(!activeLightbox) } diff --git a/src/view/com/util/Views.tsx b/src/view/com/util/Views.tsx index 38c3f20904..cd3ecf533d 100644 --- a/src/view/com/util/Views.tsx +++ b/src/view/com/util/Views.tsx @@ -1,6 +1,5 @@ -import {forwardRef} from 'react' -import {type FlatListComponent} from 'react-native' -import {View, type ViewProps} from 'react-native' +import {forwardRef, memo} from 'react' +import {type FlatListComponent, View, type ViewProps} from 'react-native' import Animated from 'react-native-reanimated' import {type FlatListPropsWithLayout} from 'react-native-reanimated' @@ -10,7 +9,7 @@ import {type FlatListPropsWithLayout} from 'react-native-reanimated' * Avoid using `FlatList_INTERNAL` and use `List` where possible. * The types are a bit wrong on `FlatList_INTERNAL` */ -export const FlatList_INTERNAL = Animated.FlatList +export const FlatList_INTERNAL = memo(Animated.FlatList) export type FlatList_INTERNAL = Omit< FlatListComponent>, 'CellRendererComponent'