Installation
Install the Smart TV Query package and set up your application for efficient data fetching.
Package Installation
Install the package using your preferred package manager:
▸
pnpm add @smart-tv/query
Requirements
Peer Dependencies
• react ^18.0.0
- React 18 or higher
• react-dom ^18.0.0
- React DOM 18 or higher
Runtime Requirements
• Modern Browser: Support for ES2020+ features
• Fetch API: Native fetch support (or polyfill)
• TypeScript: Optional but recommended (v4.5+)
Basic Setup
Set up the QueryClient and wrap your app with the QueryClientProvider:
1. Create Query Client
// src/lib/queryClient.ts
import { QueryClient } from '@smart-tv/query';
export const queryClient = new QueryClient({
defaultOptions: {
staleTime: 5 * 60 * 1000, // 5 minutes - how long data stays fresh
cacheTime: 10 * 60 * 1000, // 10 minutes - how long data stays in cache
refetchOnWindowFocus: true,
refetchOnMount: true,
retry: 2, // retry failed requests 2 times
}
});
2. Wrap Your App
// src/App.tsx
import React from 'react';
import { QueryClientProvider } from '@smart-tv/query';
import { queryClient } from './lib/queryClient';
import { HomePage } from './pages/HomePage';
function App() {
return (
<QueryClientProvider client={queryClient}>
<HomePage />
</QueryClientProvider>
);
}
export default App;
3. Use in Components
// src/components/MovieList.tsx
import React from 'react';
import { useQuery } from '@smart-tv/query';
interface Movie {
id: number;
title: string;
genre: string;
}
export function MovieList() {
const { data, error, status, refetch } = useQuery<Movie[]>(
['movies'],
async () => {
const response = await fetch('/api/movies');
if (!response.ok) {
throw new Error('Failed to fetch movies');
}
return response.json();
}
);
if (status === 'loading') {
return <div>Loading movies...</div>;
}
if (status === 'error') {
return <div>Error: {error?.message}</div>;
}
return (
<div>
<h2>Movies</h2>
<button onClick={() => refetch()}>Refresh</button>
<ul>
{data?.map(movie => (
<li key={movie.id}>
{movie.title} - {movie.genre}
</li>
))}
</ul>
</div>
);
}
Legacy Smart TV Setup
For older Smart TV platforms that don't support modern fetch API, use the built-in XHR fetcher for maximum compatibility.
Using XHR Fetcher
// src/lib/api.ts
import { xhrFetcher, tvFetch } from '@smart-tv/query';
// Create API functions using XHR fetcher
export const api = {
// Basic usage with xhrFetcher
getMovies: async () => {
const response = await xhrFetcher('/api/movies');
return response.json();
},
// Advanced usage with options for Smart TV optimization
getMovieDetails: async (id: number) => {
const response = await tvFetch(`/api/movies/${id}`, {
method: 'GET',
timeout: 15000, // 15 second timeout for slow TV networks
responseType: 'json',
headers: {
'Accept': 'application/json',
'X-Device-Type': 'smart-tv'
},
withCredentials: true, // Include cookies for authentication
onDownloadProgress: (loaded, total) => {
console.log(`Loading movie details: ${Math.round((loaded / total) * 100)}%`);
}
});
return response.json();
},
// POST request with JSON body
createWatchlistItem: async (movieId: number) => {
const response = await xhrFetcher('/api/watchlist', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: { movieId },
timeout: 10000
});
return response.json();
}
};
Smart TV Component Example
// src/components/TVMovieList.tsx
import React from 'react';
import { useQuery } from '@smart-tv/query';
import { api } from '../lib/api';
export function TVMovieList() {
const { data, error, status, refetch } = useQuery(
['tv-movies'],
api.getMovies,
{
staleTime: 10 * 60 * 1000, // 10 minutes - longer for TV
cacheTime: 30 * 60 * 1000, // 30 minutes cache
refetchOnWindowFocus: false, // TV apps don't lose focus
retry: 3, // More retries for unreliable TV networks
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000)
}
);
if (status === 'loading') {
return (
<div className="tv-loading flex flex-col items-center justify-center p-8 bg-gray-100 dark:bg-gray-800 rounded-lg">
<div className="loading-spinner w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mb-4" />
<p className="text-gray-700 dark:text-gray-300">Loading movies for your Smart TV...</p>
</div>
);
}
if (status === 'error') {
return (
<div className="tv-error p-6 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
<h3 className="text-lg font-semibold text-red-900 dark:text-red-200 mb-2">Connection Error</h3>
<p className="text-red-800 dark:text-red-300 mb-4">Unable to load movies. Please check your internet connection.</p>
<button
onClick={() => refetch()}
className="px-4 py-2 bg-red-600 hover:bg-red-700 dark:bg-red-700 dark:hover:bg-red-600 text-white rounded-lg transition-colors"
>
Try Again
</button>
</div>
);
}
return (
<div className="tv-movie-grid grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4">
{data?.map(movie => (
<div key={movie.id} className="tv-movie-card bg-white dark:bg-gray-800 rounded-lg shadow-md hover:shadow-lg transition-shadow">
<img src={movie.poster} alt={movie.title} className="w-full h-auto rounded-t-lg" />
<div className="p-3">
<h3 className="font-semibold text-gray-900 dark:text-gray-100 truncate">{movie.title}</h3>
<p className="text-sm text-gray-600 dark:text-gray-400">{movie.genre}</p>
</div>
</div>
))}
</div>
);
}
XHR Options Reference
Available XHR Options:
- •
method
- HTTP method (GET, POST, PUT, DELETE) - •
headers
- Request headers object - •
body
- Request body (auto-stringified for objects) - •
timeout
- Request timeout in milliseconds - •
responseType
- Response type (json, text, blob, arraybuffer) - •
withCredentials
- Include cookies/credentials - •
onUploadProgress
- Upload progress callback - •
onDownloadProgress
- Download progress callback - •
signal
- AbortSignal for request cancellation
TypeScript Setup
For the best TypeScript experience, configure your project with proper types:
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "DOM.Iterable", "ES2020"],
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"jsx": "react-jsx",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
Global Type Declarations
// src/types/query.d.ts
declare module '@smart-tv/query' {
interface QueryClient {
// Add custom methods if extending the client
}
interface DefaultOptions {
// Extend default options if needed
}
}
Environment Configuration
Development Setup
// src/lib/queryClient.dev.ts
import { QueryClient } from '@smart-tv/query';
export const queryClient = new QueryClient({
defaultOptions: {
staleTime: 0, // Always refetch in development
cacheTime: 5 * 60 * 1000, // 5 minutes cache
refetchOnWindowFocus: true,
refetchOnMount: true,
retry: 1, // Less retries in development
}
});
// Enable query devtools if available
if (process.env.NODE_ENV === 'development') {
// Optional: Add development-specific debugging
console.log('Query client initialized in development mode');
}
Production Setup
// src/lib/queryClient.prod.ts
import { QueryClient } from '@smart-tv/query';
export const queryClient = new QueryClient({
defaultOptions: {
staleTime: 5 * 60 * 1000, // 5 minutes fresh
cacheTime: 30 * 60 * 1000, // 30 minutes cache
refetchOnWindowFocus: false, // Disable on focus for TV
refetchOnMount: true,
retry: 3, // More retries in production
}
});
Smart TV Optimized Setup
// src/lib/queryClient.tv.ts
import { QueryClient } from '@smart-tv/query';
export const queryClient = new QueryClient({
defaultOptions: {
staleTime: 10 * 60 * 1000, // 10 minutes - longer for TV
cacheTime: 60 * 60 * 1000, // 1 hour - aggressive caching
refetchOnWindowFocus: false, // TV apps don't lose focus
refetchOnMount: false, // Prevent unnecessary refetches
retry: 2,
retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000),
}
});
// TV-specific optimizations
if (typeof window !== 'undefined') {
// Prevent network requests when device is in standby
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
queryClient.cancelQueries();
}
});
}
Next Steps
Troubleshooting
⚠️Common Issues
- •Fetch not defined:Ensure your environment supports the Fetch API or use the built-in XHR fetcher
- •React version mismatch:Make sure you're using React 18+ for full compatibility
- •TypeScript errors:Update to TypeScript 4.5+ for best compatibility and type safety
- •Bundle size:Use tree-shaking with modern bundlers (Webpack 5+, Vite) to reduce bundle size
💡Pro Tips
- •Use the
xhrFetcher
for older Smart TV platforms - •Configure longer
staleTime
andcacheTime
for TV apps - •Enable request retries with exponential backoff for unreliable TV networks