All skills
asyrafhussin avatar

/state-management

@10bb16e

React Query and Zustand patterns for state management. Use when implementing data fetching, caching, mutations, or client-side state. Triggers on tasks involving useQuery, useMutation, Zustand stores, caching, or state management.

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/state-management

This session only. Nothing lands on disk.

rulesrq-placeholder-data.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Placeholder Data for Immediate Display

Impact: MEDIUM

Placeholder data provides temporary data to display while the actual query is loading. Unlike initialData, it doesn't persist to the cache and doesn't affect staleness.

Bad Example

// Anti-pattern: Using initialData when you want temporary display data
const { data: user } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
  initialData: { name: 'Loading...', email: '' }, // This goes into cache!
  // Cache now contains fake data until refetch
});

// Anti-pattern: Conditional rendering that causes layout shift
function UserProfile({ userId }: { userId: string }) {
  const { data, isLoading } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId),
  });

  if (isLoading) {
    return <Skeleton />; // Layout might shift when data loads
  }

  return <ProfileCard user={data} />;
}

// Anti-pattern: placeholderData that doesn't match data shape
const { data } = useQuery({
  queryKey: ['users'],
  queryFn: fetchUsers,
  placeholderData: [], // Missing expected fields that component might access
});

Good Example

// Use placeholderData for immediate display
const { data: user, isPlaceholderData } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
  placeholderData: {
    id: userId,
    name: 'Loading...',
    email: '',
    avatar: '/placeholder-avatar.png',
  },
});

// Show loading state while using placeholder
return (
  <div className={isPlaceholderData ? 'opacity-50' : ''}>
    <ProfileCard user={user} />
  </div>
);

// Use previous data as placeholder when filters change
function ProductList({ category }: { category: string }) {
  const { data: products, isPlaceholderData } = useQuery({
    queryKey: ['products', category],
    queryFn: () => fetchProducts(category),
    placeholderData: (previousData) => previousData, // Keep showing old data
  });

  return (
    <div className={isPlaceholderData ? 'loading' : ''}>
      <ProductGrid products={products} />
    </div>
  );
}

// Generate placeholder from query client cache
function UserDetail({ userId }: { userId: string }) {
  const queryClient = useQueryClient();

  const { data: user } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId),
    placeholderData: () => {
      // Look for user in the users list cache
      const users = queryClient.getQueryData<User[]>(['users']);
      return users?.find(u => u.id === userId);
    },
  });

  return <UserProfile user={user} />;
}

// Placeholder with realistic structure
interface Post {
  id: string;
  title: string;
  content: string;
  author: User;
  createdAt: string;
}

const createPostPlaceholder = (postId: string): Post => ({
  id: postId,
  title: '...',
  content: '...',
  author: {
    id: '',
    name: 'Loading...',
    avatar: '/placeholder.png',
  },
  createdAt: new Date().toISOString(),
});

function PostDetail({ postId }: { postId: string }) {
  const { data: post, isPlaceholderData } = useQuery({
    queryKey: ['post', postId],
    queryFn: () => fetchPost(postId),
    placeholderData: () => createPostPlaceholder(postId),
  });

  return (
    <article aria-busy={isPlaceholderData}>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
      <AuthorBadge author={post.author} />
    </article>
  );
}

// Conditional placeholder — only use previous data if query is similar
const { data, isPlaceholderData } = useQuery({
  queryKey: ['search', searchTerm],
  queryFn: () => search(searchTerm),
  placeholderData: (previousData, previousQuery) => {
    // Only use previous data if it's from a similar query
    if (previousQuery?.queryKey[1]?.toString().startsWith(searchTerm[0])) {
      return previousData;
    }
    return undefined;
  },
});

Why

  1. Instant UI: Users see content structure immediately instead of loading spinners, reducing perceived latency.

  2. Layout Stability: Placeholder data maintains layout while real data loads, preventing cumulative layout shift.

  3. Cache Integrity: Unlike initialData, placeholder data never enters the cache, so stale checks work correctly.

  4. Smooth Transitions: Using previous data as placeholder creates smooth transitions when query parameters change.

  5. Progressive Enhancement: Components can render optimistically and enhance when real data arrives.

  6. Accessibility: The isPlaceholderData flag allows proper ARIA states and visual loading indicators.

Placeholder vs Initial Data:

Aspect placeholderData initialData
Enters cache No Yes
Affects staleness No Yes (with staleTime)
Available on first render Yes Yes
Triggers refetch Always Depends on staleTime
Use case Temporary display Known good data

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill provides secure and comprehensive documentation for managing application state using React Query and Zustand. It includes critical security warnings against storing sensitive data in local storage and promotes best practices for data fetching, caching, and error handling. No malicious patterns or security vulnerabilities were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    32 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 10bb16e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
metadata
{
  "author": "agent-skills",
  "version": "1.1.0"
}

README badge

README badge for asyrafhussin/agent-skills/state-management