@@ -17,26 +17,36 @@ type FlashListScrollKeyProps<T> = {
1717
1818export default function useFlashListScrollKey < T > ( { data, keyExtractor, initialScrollKey, onStartReached} : FlashListScrollKeyProps < T > ) {
1919 const [ isInitialRender , setIsInitialRender ] = useState ( true ) ;
20+ const [ hasLinkingSettled , setHasLinkingSettled ] = useState ( ! initialScrollKey ) ;
2021
21- // After the first render with sliced data, give FlashList one frame to lay out,
22- // then switch to the full data array. maintainVisibleContentPosition keeps the target pinned.
22+ // Two-frame handoff for deep-link:
23+ // RAF 1: switch from sliced data to the full array — FlashList's default MVCP pins the
24+ // linked item through the data swap.
25+ // RAF 2: pinning has happened, disable MVCP so it doesn't cause later jumps.
2326 useEffect ( ( ) => {
2427 if ( ! isInitialRender || ! initialScrollKey ) {
2528 return ;
2629 }
27- requestAnimationFrame ( ( ) => setIsInitialRender ( false ) ) ;
30+ requestAnimationFrame ( ( ) => {
31+ setIsInitialRender ( false ) ;
32+ requestAnimationFrame ( ( ) => setHasLinkingSettled ( true ) ) ;
33+ } ) ;
2834 } , [ isInitialRender , initialScrollKey ] ) ;
2935
36+ // `undefined` = leave FlashList's default (MVCP enabled) while we're still pinning the linked item.
37+ // `{disabled: true}` once that's done so MVCP can't interfere afterward.
38+ const maintainVisibleContentPosition : FlashListProps < T > [ 'maintainVisibleContentPosition' ] = hasLinkingSettled ? { disabled : true } : undefined ;
39+
3040 if ( ! isInitialRender || ! initialScrollKey ) {
31- return { displayedData : data , onStartReached} ;
41+ return { displayedData : data , onStartReached, maintainVisibleContentPosition } ;
3242 }
3343
3444 const targetIndex = data . findIndex ( ( item , index ) => keyExtractor ( item , index ) === initialScrollKey ) ;
3545 if ( targetIndex <= 0 ) {
36- return { displayedData : data , onStartReached} ;
46+ return { displayedData : data , onStartReached, maintainVisibleContentPosition } ;
3747 }
3848
3949 // On the first render, slice from the target onward so the target item
4050 // appears at the visual bottom of the inverted list — no scrolling needed.
41- return { displayedData : data . slice ( targetIndex ) , onStartReached : ( ) => { } } ;
51+ return { displayedData : data . slice ( targetIndex ) , onStartReached : ( ) => { } , maintainVisibleContentPosition } ;
4252}
0 commit comments