From 53f8af6ccbcbfee67090f66eb5f5af61ad0274c5 Mon Sep 17 00:00:00 2001 From: Oskar Eichler <62393985+OskarEichler@users.noreply.github.com> Date: Fri, 28 Aug 2026 06:35:16 +0300 Subject: [PATCH] fix(example): preserve Twitter pages across asynchronous callbacks Own and clean up page/refresh timers, prevent duplicate page requests, use a cursor without mutating the remaining source array and preserve concurrently loaded pages. Import DebugContext directly. --- fixture/react-native/src/twitter/Twitter.tsx | 47 +++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/fixture/react-native/src/twitter/Twitter.tsx b/fixture/react-native/src/twitter/Twitter.tsx index 4ddf5dd79..3afed9534 100644 --- a/fixture/react-native/src/twitter/Twitter.tsx +++ b/fixture/react-native/src/twitter/Twitter.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useRef, useState } from "react"; +import React, { useContext, useEffect, useRef, useState } from "react"; import { View, Text, @@ -8,7 +8,7 @@ import { } from "react-native"; import { FlashList, FlashListRef } from "@shopify/flash-list"; -import { DebugContext } from "../Debug"; +import { DebugContext } from "../Debug/DebugContext"; import TweetCell from "./TweetCell"; import { tweets as tweetsData } from "./data/tweets"; @@ -27,9 +27,22 @@ const Twitter = ({ }: TwitterProps) => { const debugContext = useContext(DebugContext); const [refreshing, setRefreshing] = useState(false); - const remainingTweets = useRef([...tweetsData].splice(10, tweetsData.length)); - const [tweets, setTweets] = useState( - debugContext.pagingEnabled ? [...tweetsData].splice(0, 10) : tweetsData + const nextTweetIndex = useRef( + debugContext.pagingEnabled ? 10 : tweetsData.length + ); + const refreshTimeout = useRef | null>(null); + const pageTimeout = useRef | null>(null); + const [tweets, setTweets] = useState(() => + debugContext.pagingEnabled ? tweetsData.slice(0, 10) : tweetsData + ); + useEffect( + () => () => { + if (refreshTimeout.current !== null) clearTimeout(refreshTimeout.current); + if (pageTimeout.current !== null) clearTimeout(pageTimeout.current); + refreshTimeout.current = null; + pageTimeout.current = null; + }, + [] ); const viewabilityConfig = useRef({ waitForInteraction: false, @@ -50,22 +63,32 @@ const Twitter = ({ }} refreshing={refreshing} onRefresh={() => { + if (refreshTimeout.current !== null) return; setRefreshing(true); - setTimeout(() => { + refreshTimeout.current = setTimeout(() => { + refreshTimeout.current = null; setRefreshing(false); - const reversedTweets = [...tweets]; - reversedTweets.reverse(); - setTweets(reversedTweets); + setTweets((previous) => [...previous].reverse()); }, 500); }} // @ts-ignore - Type compatibility issue between different React versions CellRendererComponent={CellRendererComponent} onEndReached={() => { - if (!debugContext.pagingEnabled) { + if ( + !debugContext.pagingEnabled || + pageTimeout.current !== null || + nextTweetIndex.current >= tweetsData.length + ) { return; } - setTimeout(() => { - setTweets([...tweets, ...remainingTweets.current.splice(0, 10)]); + pageTimeout.current = setTimeout(() => { + pageTimeout.current = null; + const page = tweetsData.slice( + nextTweetIndex.current, + nextTweetIndex.current + 10 + ); + nextTweetIndex.current += page.length; + setTweets((previous) => [...previous, ...page]); }, 1000); }} ListHeaderComponent={Header}