React Hooks
The Seekora UI SDK provides several hooks for building custom search experiences.
useSeekoraSearch
Hook for performing searches with the Seekora client.
Signature
function useSeekoraSearch(options: {
client: SeekoraClient;
autoTrack?: boolean;
}): {
search: (query: string, options?: SearchOptions) => Promise<SearchResponse>;
results: SearchResponse | null;
loading: boolean;
error: Error | null;
context: SearchContext | null;
clearResults: () => void;
};
Options
| Option | Type | Default | Description |
|---|---|---|---|
client | SeekoraClient | Required | Seekora client instance |
autoTrack | boolean | true | Auto-track search events |
Returns
| Property | Type | Description |
|---|---|---|
search | function | Perform search function |
results | SearchResponse | null | Search results |
loading | boolean | Loading state |
error | Error | null | Error state |
context | SearchContext | null | Search context for analytics |
clearResults | function | Clear results function |
Example
import { useSeekoraSearch } from '@seekora-ai/ui-sdk-react';
function CustomSearch() {
const { search, results, loading, error, clearResults } = useSeekoraSearch({
client,
autoTrack: true,
});
const handleSubmit = async (query: string) => {
await search(query, {
per_page: 20,
facet_by: 'category,brand',
});
};
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{results?.results.map((result) => (
<div key={result.id}>{result.title}</div>
))}
</div>
);
}
useQuerySuggestions
Hook for fetching query suggestions with debouncing.
Signature
function useQuerySuggestions(options: {
client: SeekoraClient;
query: string;
enabled?: boolean;
debounceMs?: number;
maxSuggestions?: number;
options?: QuerySuggestionsOptions;
}): {
suggestions: string[];
loading: boolean;
error: Error | null;
};
Options
| Option | Type | Default | Description |
|---|---|---|---|
client | SeekoraClient | Required | Seekora client |
query | string | Required | Current query |
enabled | boolean | true | Enable fetching |
debounceMs | number | 300 | Debounce delay |
maxSuggestions | number | 10 | Max suggestions |
options | QuerySuggestionsOptions | - | Additional options |
Example
import { useState } from 'react';
import { useQuerySuggestions } from '@seekora-ai/ui-sdk-react';
function Autocomplete() {
const [query, setQuery] = useState('');
const [showSuggestions, setShowSuggestions] = useState(false);
const { suggestions, loading } = useQuerySuggestions({
client,
query,
enabled: query.length >= 2 && showSuggestions,
debounceMs: 300,
maxSuggestions: 8,
});
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
onFocus={() => setShowSuggestions(true)}
onBlur={() => setTimeout(() => setShowSuggestions(false), 200)}
/>
{showSuggestions && suggestions.length > 0 && (
<ul className="suggestions">
{loading ? (
<li>Loading...</li>
) : (
suggestions.map((suggestion, i) => (
<li
key={i}
onClick={() => {
setQuery(suggestion);
setShowSuggestions(false);
}}
>
{suggestion}
</li>
))
)}
</ul>
)}
</div>
);
}
useSearchState
Hook for accessing and managing search state.
Signature
function useSearchState(): {
// Query
query: string;
setQuery: (query: string) => void;
// Results
results: SearchResponse | null;
loading: boolean;
error: Error | null;
// Pagination
currentPage: number;
setPage: (page: number) => void;
totalPages: number;
// Items per page
itemsPerPage: number;
setItemsPerPage: (count: number) => void;
// Refinements
refinements: Refinement[];
addRefinement: (field: string, value: string) => void;
removeRefinement: (field: string, value: string) => void;
clearRefinements: () => void;
hasRefinement: (field: string, value: string) => boolean;
// Sorting
sortBy: string;
setSortBy: (value: string) => void;
};
Example
import { useSearchState } from '@seekora-ai/ui-sdk-react';
function SearchControls() {
const {
query,
setQuery,
results,
currentPage,
setPage,
totalPages,
refinements,
addRefinement,
removeRefinement,
clearRefinements,
sortBy,
setSortBy,
} = useSearchState();
return (
<div>
{/* Query */}
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>
{/* Active Refinements */}
<div className="refinements">
{refinements.map((ref) => (
<span key={`${ref.field}-${ref.value}`}>
{ref.field}: {ref.value}
<button onClick={() => removeRefinement(ref.field, ref.value)}>
×
</button>
</span>
))}
{refinements.length > 0 && (
<button onClick={clearRefinements}>Clear all</button>
)}
</div>
{/* Sort */}
<select value={sortBy} onChange={(e) => setSortBy(e.target.value)}>
<option value="relevance:desc">Relevance</option>
<option value="price:asc">Price: Low to High</option>
<option value="price:desc">Price: High to Low</option>
</select>
{/* Results Count */}
<p>{results?.totalResults ?? 0} results</p>
{/* Pagination */}
<div className="pagination">
<button
disabled={currentPage === 1}
onClick={() => setPage(currentPage - 1)}
>
Previous
</button>
<span>
Page {currentPage} of {totalPages}
</span>
<button
disabled={currentPage === totalPages}
onClick={() => setPage(currentPage + 1)}
>
Next
</button>
</div>
</div>
);
}
useAnalytics
Hook for tracking analytics events. Requires a Seekora client (from context or passed in options).
Signature
function useAnalytics(options: {
client: SeekoraClient;
enabled?: boolean;
}): {
trackEvent: (eventType: string, payload: Partial<DataTypesEventPayload>, context?: SearchContext) => Promise<void>;
trackClick: (resultId: string, result: any, context?: SearchContext, position?: number) => Promise<void>;
trackConversion: (resultId: string, result: any, value?: number, currency?: string, context?: SearchContext) => Promise<void>;
trackBatch: (events: (Partial<DataTypesEventPayload> & { event_name?: string })[], context?: SearchContext) => Promise<void>;
};
Example
When used inside SearchProvider, get client from useSearchContext():
import { useAnalytics, useSearchContext, useSearchState } from '@seekora-ai/ui-sdk-react';
function ProductCard({ product, index }) {
const { client } = useSearchContext();
const { trackClick, trackConversion } = useAnalytics({ client });
const { results } = useSearchState();
const handleClick = async () => {
await trackClick(product.id, product, results?.context ?? undefined, index + 1);
navigate(`/product/${product.id}`);
};
const handleAddToCart = async () => {
await trackConversion(product.id, product, product.price, 'USD', results?.context ?? undefined);
addToCart(product);
};
return (
<div className="product-card" onClick={handleClick}>
<img src={product.image} alt={product.title} />
<h3>{product.title}</h3>
<p>${product.price}</p>
<button onClick={handleAddToCart}>Add to Cart</button>
</div>
);
}
useQuerySuggestionsEnhanced
Enhanced hook with keyboard navigation support.
Signature
function useQuerySuggestionsEnhanced(options: {
client: SeekoraClient;
query: string;
onSelect?: (suggestion: string) => void;
enabled?: boolean;
}): {
suggestions: string[];
loading: boolean;
error: Error | null;
selectedIndex: number;
setSelectedIndex: (index: number) => void;
handleKeyDown: (e: KeyboardEvent) => void;
selectCurrent: () => void;
};
Example
import { useState, useRef } from 'react';
import { useQuerySuggestionsEnhanced } from '@seekora-ai/ui-sdk-react';
function EnhancedAutocomplete() {
const [query, setQuery] = useState('');
const inputRef = useRef<HTMLInputElement>(null);
const {
suggestions,
loading,
selectedIndex,
handleKeyDown,
} = useQuerySuggestionsEnhanced({
client,
query,
onSelect: (suggestion) => {
setQuery(suggestion);
performSearch(suggestion);
},
});
return (
<div>
<input
ref={inputRef}
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyDown={handleKeyDown}
/>
{suggestions.length > 0 && (
<ul>
{suggestions.map((suggestion, i) => (
<li
key={i}
className={i === selectedIndex ? 'selected' : ''}
>
{suggestion}
</li>
))}
</ul>
)}
</div>
);
}
useSmartSuggestions
Hook with caching and smart prefetching.
Signature
function useSmartSuggestions(options: {
client: SeekoraClient;
query: string;
cacheTime?: number;
prefetch?: boolean;
}): {
suggestions: string[];
loading: boolean;
error: Error | null;
cached: boolean;
};
Example
import { useSmartSuggestions } from '@seekora-ai/ui-sdk-react';
function SmartAutocomplete() {
const [query, setQuery] = useState('');
const { suggestions, loading, cached } = useSmartSuggestions({
client,
query,
cacheTime: 60000, // Cache for 1 minute
prefetch: true,
});
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
{loading && !cached && <span>Loading...</span>}
{suggestions.map((s, i) => (
<div key={i}>{s}</div>
))}
</div>
);
}
useSuggestionsAnalytics
Hook for tracking suggestion analytics.
Signature
function useSuggestionsAnalytics(options?: {
client?: SeekoraClient;
}): {
trackSuggestionView: (suggestions: string[]) => void;
trackSuggestionClick: (suggestion: string, position: number) => void;
};
Example
import { useSuggestionsAnalytics } from '@seekora-ai/ui-sdk-react';
function AnalyticsAwareSuggestions({ suggestions }) {
const { trackSuggestionView, trackSuggestionClick } = useSuggestionsAnalytics();
useEffect(() => {
if (suggestions.length > 0) {
trackSuggestionView(suggestions);
}
}, [suggestions]);
return (
<ul>
{suggestions.map((suggestion, i) => (
<li
key={i}
onClick={() => {
trackSuggestionClick(suggestion, i + 1);
selectSuggestion(suggestion);
}}
>
{suggestion}
</li>
))}
</ul>
);
}
Custom Hook Examples
useDebounce
function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debouncedValue;
}
// Usage with search
function DebouncedSearch() {
const [query, setQuery] = useState('');
const debouncedQuery = useDebounce(query, 300);
const { search, results } = useSeekoraSearch({ client });
useEffect(() => {
if (debouncedQuery) {
search(debouncedQuery);
}
}, [debouncedQuery]);
return (
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
);
}
useInfiniteSearch
function useInfiniteSearch(options: { client: SeekoraClient }) {
const [results, setResults] = useState<any[]>([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const [loading, setLoading] = useState(false);
const loadMore = async (query: string) => {
if (loading || !hasMore) return;
setLoading(true);
const response = await options.client.search(query, {
page,
per_page: 20,
});
setResults((prev) => [...prev, ...response.results]);
setHasMore(response.results.length === 20);
setPage((p) => p + 1);
setLoading(false);
};
const reset = () => {
setResults([]);
setPage(1);
setHasMore(true);
};
return { results, loadMore, hasMore, loading, reset };
}
Next Steps
- Premium Suggestions - Rich autocomplete components
- Theming - Customize appearance