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-query-functions.md

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

Query Functions Best Practices

Impact: CRITICAL

Query functions are the data fetching logic passed to useQuery. They should be pure, handle errors properly, and return consistent data shapes.

Bad Example

// Anti-pattern: Inline query function with side effects
const { data } = useQuery({
  queryKey: ['user', userId],
  queryFn: async () => {
    // Side effect in query function
    analytics.track('user_fetched');

    const response = await fetch(`/api/users/${userId}`);
    // Not handling errors properly
    return response.json();
  },
});

// Anti-pattern: Query function that doesn't throw on error
const { data, isError } = useQuery({
  queryKey: ['posts'],
  queryFn: async () => {
    const response = await fetch('/api/posts');
    if (!response.ok) {
      // Returning error data instead of throwing
      return { error: true, message: 'Failed to fetch' };
    }
    return response.json();
  },
});

// Anti-pattern: Mutating external state in query function
let cache = {};
const { data } = useQuery({
  queryKey: ['data'],
  queryFn: async () => {
    const result = await fetchData();
    cache = result; // Mutating external state
    return result;
  },
});

Good Example

// Create reusable, testable query functions
async function fetchUser(userId: string): Promise<User> {
  const response = await fetch(`/api/users/${userId}`);

  if (!response.ok) {
    throw new Error(`Failed to fetch user: ${response.statusText}`);
  }

  return response.json();
}

async function fetchPosts(params: PostsParams): Promise<PostsResponse> {
  const searchParams = new URLSearchParams();
  if (params.page) searchParams.set('page', String(params.page));
  if (params.limit) searchParams.set('limit', String(params.limit));
  if (params.category) searchParams.set('category', params.category);

  const response = await fetch(`/api/posts?${searchParams}`);

  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new ApiError(response.status, error.message || 'Failed to fetch posts');
  }

  return response.json();
}

// Custom error class for better error handling
class ApiError extends Error {
  constructor(public status: number, message: string) {
    super(message);
    this.name = 'ApiError';
  }
}

// Usage with clean separation
const { data: user, error } = useQuery({
  queryKey: userKeys.detail(userId),
  queryFn: () => fetchUser(userId),
});

// With query function context for cancellation
const { data: posts } = useQuery({
  queryKey: postKeys.list(params),
  queryFn: async ({ signal }) => {
    const response = await fetch(`/api/posts`, { signal });
    if (!response.ok) throw new Error('Failed to fetch');
    return response.json();
  },
});

// Handle side effects outside query function
const { data } = useQuery({
  queryKey: ['user', userId],
  queryFn: () => fetchUser(userId),
});

useEffect(() => {
  if (data) {
    analytics.track('user_fetched');
  }
}, [data]);

Why

  1. Testability: Extracted query functions can be unit tested independently of React components.

  2. Error Handling: Throwing errors allows React Query to properly track error state and trigger retries.

  3. Separation of Concerns: Query functions should only fetch data; side effects belong in useEffect or mutation callbacks.

  4. Cancellation Support: Using the signal from query context enables proper request cancellation when queries are invalidated.

  5. Reusability: Standalone query functions can be reused across multiple components and even in non-React contexts.

  6. Type Safety: Explicitly typed return values ensure consistent data shapes and better TypeScript integration.

  7. Debugging: Clear error messages and proper error classes make debugging network issues much easier.

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