Skip to content
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
12 changes: 6 additions & 6 deletions hooks/useFlatListScrollRestoration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { usePathname } from 'expo-router';
import React, { useCallback, useEffect, useRef } from 'react';
import { Animated, FlatList } from 'react-native';

import { scrollPositionService } from '../services/scrollPositionService';
import logger from '../utils/logger';
import { scrollPositionService } from '../src/services/scrollPositionService';
import { logger } from '../src/utils/logger';

export interface UseFlatListScrollRestorationOptions {
/**
Expand Down Expand Up @@ -97,9 +97,9 @@ export const useFlatListScrollRestoration = (
// Content changed - clear old position to prevent invalid restores
if (contentHeightRef.current > 0) {
logger.debug(`FlatList content changed for ${screenId}, clearing position`);
scrollPositionService.clearPosition(screenId).catch((e) =>
logger.error('Failed to clear position on data change', e)
);
scrollPositionService
.clearPosition(screenId)
.catch(e => logger.error('Failed to clear position on data change', e));
lastSavedOffsetRef.current = 0;
}
contentHeightRef.current = contentHeight;
Expand Down Expand Up @@ -198,7 +198,7 @@ export const useFlatListScrollRestoration = (
// Clear position if index becomes invalid
scrollPositionService
.clearPosition(screenId)
.catch((e) => logger.error('Failed to clear position on index failure', e));
.catch(e => logger.error('Failed to clear position on index failure', e));
},
[screenId]
);
Expand Down
38 changes: 24 additions & 14 deletions hooks/useScrollRestoration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@ import { usePathname } from 'expo-router';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Animated, ScrollView } from 'react-native';

import { scrollPositionService } from '../services/scrollPositionService';
import logger from '../utils/logger';
import { logger } from '../src/utils/logger';

const scrollPositionStore = new Map<string, { offset: number }>();

const scrollPositionService = {
async getPosition(screenId: string) {
return scrollPositionStore.get(screenId) ?? null;
},
async savePosition(screenId: string, offset: number) {
scrollPositionStore.set(screenId, { offset });
},
};

export interface UseScrollRestorationOptions {
/**
Expand Down Expand Up @@ -79,11 +89,11 @@ export const useScrollRestoration = (
const saveDelay = options.saveDelay ?? 500;
const minDistanceThreshold = options.minDistanceThreshold ?? 50;
const scrollToTopOnFirstLoad = options.scrollToTopOnFirstLoad !== false;

const { onChange, onRestored, animatedValue } = options;
const [isFirstLoad, setIsFirstLoad] = useState(true);
const lastSavedOffsetRef = useRef<number>(0);
const saveTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
const isNavigatingBackRef = useRef(false);
const saveTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
// const isNavigatingBackRef = useRef(false);

// Detect when we're navigating back
useEffect(() => {
Expand Down Expand Up @@ -118,11 +128,11 @@ export const useScrollRestoration = (
});

// Update animated value if provided
if (options.animatedValue) {
options.animatedValue.setValue(saved.offset);
if (animatedValue) {
animatedValue.setValue(saved.offset);
}

options.onRestored?.(saved.offset);
onRestored?.(saved.offset);
}
}, 0);
} else if (isFirstLoad && scrollToTopOnFirstLoad) {
Expand All @@ -149,21 +159,21 @@ export const useScrollRestoration = (
});
}
};
}, [screenId, isFirstLoad, scrollToTopOnFirstLoad, scrollRef])
}, [screenId, isFirstLoad, scrollToTopOnFirstLoad, scrollRef, animatedValue, onRestored])
);

// Handle scroll events
// Handle scroll events to save position
const handleScroll = useCallback(
(event: { nativeEvent: { contentOffset: { y: number } } }) => {
const offset = event.nativeEvent.contentOffset.y;

// Update animated value if provided
if (options.animatedValue) {
options.animatedValue.setValue(offset);
if (animatedValue) {
animatedValue.setValue(offset);
}

// Call onChange callback
options.onChange?.(offset);
onChange?.(offset);

// Check if scroll distance is significant
const distance = Math.abs(offset - lastSavedOffsetRef.current);
Expand All @@ -187,7 +197,7 @@ export const useScrollRestoration = (
}
}, saveDelay);
},
[screenId, saveDelay, minDistanceThreshold, options]
[screenId, saveDelay, minDistanceThreshold, animatedValue, onChange]
);

// Cleanup timeouts on unmount
Expand Down
Loading
Loading