Skip to main content

Command Palette

Search for a command to run...

InitialData vs PlaceholderData in React Query

Updated
3 min read
InitialData vs PlaceholderData in React Query
T

Just a guy who loves to write code and watch anime.

initialData: "Real" Data That Gets Cached

This is treated as actual data that came from your API. It gets stored in the cache and affects query states:

function useUserProfile(userId) {
  return useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId),
    initialData: () => {
      // Maybe from another query's cache
      // But doesn't have to be
      const cachedUser = queryClient.getQueryData(['users'])
        ?.find(user => user.id === userId)
      return cachedUser
    }
  })
}

// Or static data you know is valid
function useAppConfig() {
  return useQuery({
    queryKey: ['config'],
    queryFn: fetchConfig,
    initialData: { theme: 'light', language: 'en' }, // Default config
    staleTime: 5 * 60 * 1000
  })
}

Key behaviors:

  • isLoading will be false immediately

  • data is available right away

  • Gets stored in cache with the query key

  • If stale, will trigger a background refetch

  • Perfect for seeding cache from other sources

placeholderData: "Fake" Data for UI Only

This is just for show → it doesn't get cached and doesn't affect the query lifecycle:

function useSearchResults(query) {
  return useQuery({
    queryKey: ['search', query],
    queryFn: () => searchAPI(query),
    placeholderData: (previousData) => previousData, // Show previous search results
    enabled: query.length > 2
  })
}

// Or static placeholder
function useProductList(category) {
  return useQuery({
    queryKey: ['products', category],
    queryFn: () => fetchProducts(category),
    placeholderData: [
      { id: 1, name: 'Loading...', price: 0 },
      { id: 2, name: 'Loading...', price: 0 },
      { id: 3, name: 'Loading...', price: 0 }
    ]
  })
}

Key behaviors:

  • isLoading stays true until real data arrives

  • data shows placeholder but isPlaceholderData is true

  • Not stored in cache

  • Great for smooth transitions and skeleton states

When to Use Each

Use initialData when:

  • You have actual data from another source (localStorage, other queries, SSR)

  • You want to populate the cache immediately

  • The data is "real" and valid to use

// Perfect for SSR or localStorage
function useUserPreferences() {
  return useQuery({
    queryKey: ['preferences'],
    queryFn: fetchPreferences,
    initialData: () => {
      // From localStorage or server-side rendered data
      return JSON.parse(localStorage.getItem('preferences') || '{}')
    }
  })
}

Use placeholderData when:

  • You want smooth loading transitions

  • Showing previous results while fetching new ones

  • Creating skeleton/loading states

  • The data is fake and just for UI

// Great for search - keep showing old results while fetching new ones
function useInfiniteSearch(query) {
  return useQuery({
    queryKey: ['search', query],
    queryFn: () => searchAPI(query),
    placeholderData: (previousData, previousQuery) => {
      // Show previous results while searching
      return previousData
    }
  })
}

Real-World Example: E-commerce Product Page

function ProductPage({ productId }) {
  const { data: product, isLoading, isPlaceholderData } = useQuery({
    queryKey: ['product', productId],
    queryFn: () => fetchProduct(productId),
    placeholderData: {
      id: productId,
      name: 'Loading...',
      price: 0,
      image: '/placeholder.jpg'
    }
  })

  return (
    <div>
      <h1 className={isPlaceholderData ? 'opacity-50' : ''}>
        {product.name}
      </h1>
      <img 
        src={product.image} 
        alt={product.name}
        className={isPlaceholderData ? 'animate-pulse' : ''}
      />
      <p>${product.price}</p>
      {isLoading && <div>Fetching latest data...</div>}
    </div>
  )
}

The main difference is: initialData acts like real data, while placeholderData is clearly fake. This impacts caching, loading states, and how React Query manages the data process.