Basic Usage

Learn the fundamental patterns and best practices for using qortex in your React applications.

Common Usage Patterns

Simple Data Fetching

Basic usage of useQuery hook for fetching data

import { registerFetcher, useQuery } from "qortex-react";

// Register a fetcher
registerFetcher(["users"], {
  fetcher: async () => {
    const response = await fetch("/api/users");
    return response.json();
  },
  equalityStrategy: "deep" // Use deep equality for nested objects
});

// Use in component
function UsersList() {
  const { data, isLoading, isSuccess, isError, error } = useQuery(["users"]);

  if (isLoading) return <div>Loading...</div>;
  if (isError) return <div>Error: {error?.message}</div>;
  if (isSuccess && data) {
    return (
      <ul>
        {data.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    );
  }
  return <div>No users found</div>;
}

With Parameters

Fetching data with dynamic parameters

import { registerFetcher, useQuery } from "qortex-react";

// Register fetcher with parameters
registerFetcher(["user", "id"], {
  fetcher: async (key) => {
    const [, , userId] = key;
    const response = await fetch(`/api/users/${userId}`);
    return response.json();
  },
  equalityStrategy: "shallow" // Use shallow equality for simple objects
});

// Use with parameters
function UserProfile({ userId }: { userId: string }) {
  const { data: user, isLoading, isSuccess, isError, error } = useQuery(["user", "id", userId]);

  if (isLoading) return <div>Loading user...</div>;
  if (isError) return <div>Error: {error?.message}</div>;
  if (isSuccess && user) {
    return (
      <div>
        <h2>{user.name}</h2>
        <p>{user.email}</p>
      </div>
    );
  }
  return <div>User not found</div>;
}

Error Handling

Proper error handling and fallback data

function TodosList() {
  const { data, isLoading, isSuccess, isError, error, refetch } = useQuery(["todos"], {
    placeholderData: [], // Show empty list while loading
    usePlaceholderOnError: true // Keep placeholder on error
  });

  if (isLoading) return <div>Loading todos...</div>;

  return (
    <div>
      {isError && (
        <div className="error-banner">
          <p>Error: {error?.message}</p>
          <button onClick={() => refetch()}>Retry</button>
        </div>
      )}
      {isSuccess && data && (
        <ul>
          {data.map(todo => (
            <li key={todo.id}>{todo.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

Background Updates

Automatic background refetching and cache management

// Configure for background updates
registerFetcher(["live-data"], {
  fetcher: async () => {
    const response = await fetch("/api/live-data");
    return response.json();
  },
  staleTime: 0 // Always consider stale for live data
});

function LiveData() {
  const { data, isFetching, isSuccess, isError, error } = useQuery(["live-data"], {
    refetchOnSubscribe: "always" // Refetch on every subscription
  });

  return (
    <div>
      {isFetching && <div className="loading-indicator">Updating...</div>}
      {isError && <div className="error">Error: {error?.message}</div>}
      {isSuccess && data && <div>Live data: {data.value}</div>}
    </div>
  );
}

Additional Patterns

Equality Strategies

Control how data changes are detected - strategy persists across all API calls

// Shallow equality (default) - compares only top-level properties
registerFetcher(["users"], {
  fetcher: fetchUsers,
  equalityStrategy: "shallow"
});

// Deep equality - recursively compares nested objects
registerFetcher(["user-profile"], {
  fetcher: fetchUserProfile,
  equalityStrategy: "deep"
});

// Custom equality function
registerFetcher(["todos"], {
  fetcher: fetchTodos,
  equalityFn: (a, b) => a?.length === b?.length
});

// The equalityStrategy is automatically reused in all other API calls:
setQueryData(["users"], newData); // Uses "shallow" strategy
getQueryData(["user-profile"]);   // Uses "deep" strategy
getQueryState(["todos"]);         // Uses custom equalityFn

Global Configuration

Set default options for all queries

setDefaultConfig({
  staleTime: 5 * 60 * 1000, // 5 minutes
  refetchOnSubscribe: "stale",
  throttleTime: 100,
  usePreviousDataOnError: false,
  equalityStrategy: "deep" // Default strategy for all queries
});

Simple Data Access

Use useQueryData for simple data access without loading states

import { useQueryData } from "qortex-react";

function UserCount() {
  const users = useQueryData(["users"]);
  return <div>Total users: {users?.length || 0}</div>;
}

Manual Data Updates

Update data manually from anywhere in your app

import { setQueryData } from "qortex-core";

// Update data directly
setQueryData(["todos"], newTodos);

Best Practices

✅ Do

  • • Use array keys for parameters
  • • Set appropriate stale times
  • • Choose the right equality strategy
  • • Provide placeholder data
  • • Handle loading and error states
  • • Use TypeScript for type safety

❌ Don't

  • • Use string keys with parameters
  • • Ignore error handling
  • • Set stale time too low
  • • Forget to register fetchers
  • • Mix different data fetching libraries

Ready for More?

Now that you understand the basics, explore advanced features and configuration options.