0Pricing
React Native Academy · บทเรียน

การดึงข้อมูลเบื้องหลังและการกำหนดเวลาข้อมูลเก่า

กำหนด staleTime และ cacheTime แยกตามคำค้น เปิดใช้ refetchOnReconnect เพื่อซิงค์ข้อมูลเมื่ออุปกรณ์กลับมาออนไลน์ และสร้างแบนเนอร์แสดงสถานะเครือข่าย

การดึงข้อมูลเบื้องหลังและการกำหนดเวลาข้อมูลเก่า เป็นบทเรียน React Native Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน React Native Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ

What Is Stale Data?

In React Query, data is considered stale when it is older than the configured staleTime. Stale data is not wrong — it's just potentially out of date. React Query displays stale data immediately from cache (no loading spinner) while scheduling a background refetch to get fresh data.

This stale-while-revalidate pattern is the key to why React Query feels so fast: users always see data immediately, and it silently updates in the background when needed. Understanding staleTime is essential to configuring this behavior correctly.

staleTime: How Long Data Is Fresh

staleTime is the number of milliseconds that cached data is considered fresh. During this window, React Query serves the cache without any network request — not even a background refetch. After staleTime expires, the data is still in the cache but considered stale, and a background refetch will happen next time it's needed.

The default staleTime is 0 — data is immediately stale after it's fetched! This means every component mount triggers a background refetch. Increasing staleTime dramatically reduces network traffic for data that doesn't change often.

// Default: staleTime = 0 (immediately stale)
const { data } = useQuery({
  queryKey: ['user'],
  queryFn: fetchUser,
  // Every mount triggers a background refetch!
});

// Better: give fresh data a 5-minute window
const { data } = useQuery({
  queryKey: ['user'],
  queryFn: fetchUser,
  staleTime: 5 * 60 * 1000, // 5 minutes
  // No refetch for 5 minutes after last fetch
});

Choosing the Right staleTime

The right staleTime depends on how often your data changes and how much users care about seeing the absolute latest version:

  • User profile: 10-30 minutes (rarely changes)
  • App configuration: Infinity (changes only on deploy)
  • Social feed: 30 seconds to 2 minutes (new posts frequently)
  • Live scores/prices: 0-10 seconds (must be current)

Set staleTime per-query to match the natural update frequency of each data type. One-size-fits-all staleTime leads to either too many requests or stale data in high-frequency contexts.

// Per-query staleTime based on data type:
const { data: profile } = useQuery({
  queryKey: ['profile'],
  queryFn: fetchProfile,
  staleTime: 15 * 60 * 1000, // 15 min
});

const { data: feed } = useQuery({
  queryKey: ['feed'],
  queryFn: fetchFeed,
  staleTime: 60 * 1000, // 1 min
});

const { data: config } = useQuery({
  queryKey: ['config'],
  queryFn: fetchConfig,
  staleTime: Infinity, // never stale
});

gcTime: How Long Cache Survives Without Observers

gcTime (garbage collection time) controls how long cached data stays in memory after all components observing it have unmounted. After this time the cache entry is deleted. New mounts for the same query then start fresh with a loading state.

gcTime defaults to 5 minutes. Set it higher for data you want available across navigation (e.g., the user navigates away and back). Set it lower for large data sets to save memory. gcTime must always be greater than or equal to staleTime — otherwise data could be garbage collected before it's even stale.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000,    // 5 min — no refetch window
      gcTime: 30 * 60 * 1000,       // 30 min — stay in memory
      // gcTime >= staleTime is important!
    },
  },
});

// Per-query override:
const { data } = useQuery({
  queryKey: ['large-dataset'],
  queryFn: fetchLargeDataset,
  gcTime: 60 * 1000, // free memory after 1 min offline
});

refetchOnMount Behavior

refetchOnMount controls what happens when a component that uses a query mounts. The default value true means: if data is stale, trigger a background refetch. Set to false to never refetch on mount (only use the cache). Set to 'always' to always refetch even if data is still fresh.

For screens that must always show the latest data (like a payment confirmation screen), use refetchOnMount: 'always'. For screens that are fine with slightly stale data (like a settings screen), use false to avoid unnecessary network traffic.

// Always fresh on mount — for critical data:
const { data: accountBalance } = useQuery({
  queryKey: ['balance'],
  queryFn: fetchBalance,
  refetchOnMount: 'always', // always refetch when screen opens
});

// Never refetch on mount — show cache only:
const { data: helpContent } = useQuery({
  queryKey: ['help'],
  queryFn: fetchHelp,
  refetchOnMount: false,
  staleTime: Infinity,
});

refetchOnReconnect: Updating After Going Online

refetchOnReconnect triggers background refetches for all stale queries when the device regains network connectivity. This is the core of offline-first behavior — data automatically refreshes when the connection returns without any user action.

Enable this with the onlineManager and NetInfo integration (shown in the previous lesson). The default is true, but it only fires for stale queries. With staleTime: 0, all queries refetch on reconnect. With longer staleTimes, only queries that have expired refetch.

// Configure global:
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnReconnect: true,   // default — refetch stale on reconnect
      staleTime: 2 * 60 * 1000,  // data stale after 2 min
    },
  },
});

// Per-query override:
const { data } = useQuery({
  queryKey: ['critical-data'],
  queryFn: fetchCritical,
  refetchOnReconnect: 'always', // always refetch on reconnect
});

refetchInterval: Polling

refetchInterval turns a query into a polling query that automatically refetches at a fixed interval, even without user interaction. This is useful for real-time data like live scores, stock prices, or status dashboards.

Polling stops when the app is in the background or the device is offline. Use refetchIntervalInBackground: true to continue polling in the background. Be conservative with polling intervals — frequent polls drain battery and use data.

// Poll every 30 seconds:
const { data: serverStatus } = useQuery({
  queryKey: ['server-status'],
  queryFn: fetchServerStatus,
  refetchInterval: 30 * 1000,          // poll every 30s
  refetchIntervalInBackground: false,   // stop when app in background
});

// Poll only while user is watching (conditional):
const { data: liveScore } = useQuery({
  queryKey: ['live-score', gameId],
  queryFn: () => fetchScore(gameId),
  refetchInterval: isGameLive ? 5000 : false, // poll only during live games
});

Manual Refetch

Trigger a manual refetch using the refetch function returned by useQuery. This is useful for pull-to-refresh interactions where the user explicitly requests fresh data. The refetch function always fetches regardless of staleTime.

Combine with FlatList's onRefresh and refreshing props for standard pull-to-refresh UX. The isFetching flag from useQuery indicates when a refetch is in progress.

const { data, isFetching, refetch } = useQuery({
  queryKey: ['posts'],
  queryFn: fetchPosts,
});

return (
  <FlatList
    data={data}
    renderItem={renderPost}
    keyExtractor={(item) => item.id}
    refreshing={isFetching}
    onRefresh={refetch}  // pull-to-refresh
  />
);

Prefetching Queries

Prefetching loads data into the cache before the user navigates to the screen that needs it. Use queryClient.prefetchQuery to trigger a fetch and cache the result. When the user arrives at the screen, the query resolves instantly from the warm cache.

Prefetch in the navigation handler or when hovering a list item (on web) or when a list item approaches the viewport (onViewableItemsChanged in FlatList). The prefetched data has its own staleTime so it won't immediately expire.

const queryClient = useQueryClient();

async function handlePostPress(postId) {
  // Prefetch before navigating:
  await queryClient.prefetchQuery({
    queryKey: ['post', postId],
    queryFn: () => fetchPost(postId),
    staleTime: 5 * 60 * 1000,
  });
  // Cache is now warm — navigate instantly:
  navigation.navigate('PostDetail', { postId });
}

Network Status Banner Pattern

Show users a network status banner when the device goes offline, and hide it when connectivity returns. Combine React Native's NetInfo with a context or Zustand store to broadcast network status to any component, and use React Query's background refetch to automatically sync when reconnected.

The banner should be subtle — an orange/red strip at the top or bottom indicating 'Offline mode — showing cached data'. Auto-dismiss it 2-3 seconds after the connection returns and a successful refetch completes.

import NetInfo from '@react-native-community/netinfo';

function useNetworkStatus() {
  const [isOnline, setIsOnline] = React.useState(true);

  React.useEffect(() => {
    const unsubscribe = NetInfo.addEventListener((state) => {
      setIsOnline(state.isConnected && state.isInternetReachable);
    });
    return unsubscribe;
  }, []);

  return isOnline;
}

// In root layout:
const isOnline = useNetworkStatus();
return (
  <View style={{ flex: 1 }}>
    {!isOnline && <OfflineBanner />}
    <NavigationContainer>...</NavigationContainer>
  </View>
);

Coordinating staleTime with Server Cache Headers

If your API returns HTTP cache headers (like Cache-Control: max-age=300), align your React Query staleTime with the server's cache duration. This prevents the app from refetching data that the server wouldn't have updated yet anyway, saving bandwidth and server load.

For APIs without cache headers, set staleTime based on your knowledge of how frequently the data changes. Document your staleTime decisions in comments — they are architectural choices that affect user experience and server load in non-obvious ways.

// API returns Cache-Control: max-age=300 (5 minutes)
// Match staleTime to server cache duration:
const { data: articles } = useQuery({
  queryKey: ['articles'],
  queryFn: fetchArticles,
  staleTime: 5 * 60 * 1000, // matches server max-age
  // No point refetching — server would return same data
});

// Runtime staleTime from response header:
const staleTime = parseInt(response.headers.get('Cache-Control')
  .match(/max-age=(\d+)/)?.[1] || '300') * 1000;

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: staleTime controls how long cached data is considered fresh before a background refetch is scheduled on next access, refetchOnReconnect: true automatically refreshes stale queries when network connectivity returns, and refetchInterval turns a query into a polling query that updates at a fixed interval — useful for live data. Congratulations on completing the Offline-First with React Query course — next you'll integrate Supabase as a full backend for your React Native app.

คำถามที่พบบ่อย

บทเรียน “การดึงข้อมูลเบื้องหลังและการกำหนดเวลาข้อมูลเก่า” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การดึงข้อมูลเบื้องหลังและการกำหนดเวลาข้อมูลเก่า” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส React Native Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การดึงข้อมูลเบื้องหลังและการกำหนดเวลาข้อมูลเก่า”

กำหนด staleTime และ cacheTime แยกตามคำค้น เปิดใช้ refetchOnReconnect เพื่อซิงค์ข้อมูลเมื่ออุปกรณ์กลับมาออนไลน์ และสร้างแบนเนอร์แสดงสถานะเครือข่าย คุณปฏิบัติ React Native Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน React Native Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน React Native Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การดึงข้อมูลเบื้องหลังและการกำหนดเวลาข้อมูลเก่า” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน React Native Academy นี้ได้ไหม

ได้ บทเรียน React Native Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. QueryClient, QueryClientProvider และ useQuery
  2. การเปลี่ยนแปลงด้วย useMutation และการทำให้แคชไม่ถูกต้อง
  3. การคงแคชคำค้นด้วย AsyncStorage
  4. การดึงข้อมูลเบื้องหลังและการกำหนดเวลาข้อมูลเก่า
← กลับไปที่ React Native Academy