🔍 SearchOptimizer
An optimized, framework-agnostic solution for handling search-as-you-type functionality.
📖 Table of Contents
- Overview
- Installation
- Quick Start
- API Reference
- Adapters & Hooks
- Examples
- Contributing
- Changelog
- License
📋 Overview
SearchOptimizer is a lightweight, framework-agnostic library that helps optimize search inputs with real-time results (search-as-you-type). It provides a clean, efficient way to:
- Debounce user input to reduce unnecessary API calls
- Prevent race conditions by automatically canceling outdated requests
- Apply minimum character limits before triggering searches
- Process input uniformly (trim, lowercase, etc.)
- Works with any request library or framework
⚙️ Installation
npm install search-optimizer
# or
yarn add search-optimizer
🚀 Quick Start
Basic Usage
import { createSearchOptimizer } from 'search-optimizer';
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';
// Create a search executor using fetch
const searchExecutor = createFetchExecutor({
baseUrl: 'https://api.example.com/search',
queryParam: 'q',
});
// Create the search optimizer
const searchOptimizer = createSearchOptimizer(searchExecutor, {
debounceDelay: 500,
minChars: 3,
});
// Get the search input element
const searchInput = document.getElementById('search-input');
// Connect the input to the search optimizer
searchInput.addEventListener('input', event => {
searchOptimizer.setQuery(event.target.value);
});
// Subscribe to changes in the search state
setInterval(() => {
console.log('Loading:', searchOptimizer.loading);
console.log('Results:', searchOptimizer.results);
console.log('Error:', searchOptimizer.error);
}, 1000);
React Hook Usage
import React from 'react';
import { useSearchOptimizer } from 'search-optimizer/adapters/react';
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';
function SearchComponent() {
// Create the search executor
const searchExecutor = React.useMemo(
() =>
createFetchExecutor({
baseUrl: 'https://api.example.com/search',
queryParam: 'q',
}),
[],
);
// Use the hook to manage search state
const { inputProps, loading, results, error } = useSearchOptimizer(searchExecutor, {
debounceDelay: 400,
minChars: 2,
});
return (
<div>
<input type="text" placeholder="Search..." {...inputProps} />
{loading && <div>Loading...</div>}
{results && (
<ul>
{results.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)}
{error && <div>Error: {error.message}</div>}
</div>
);
}
📖 API Reference
Core
createSearchOptimizer(executor, options)
Creates a new SearchOptimizer instance.
Parameters:
executor
: A SearchExecutor implementationoptions
: Configuration options
Returns: A SearchOptimizerResult object with methods and state properties
Options:
debounceDelay
: Debounce delay in milliseconds (default: 500)minChars
: Minimum characters required before triggering search (default: 3)trimInput
: Whether to trim the input value (default: true)lowercaseInput
: Whether to convert the input to lowercase (default: true)enableCancellation
: Whether to enable request cancellation (default: true)inputProcessor
: Custom function to process inputonSearchStart
: Callback when search startsonSearchSuccess
: Callback when search succeedsonSearchError
: Callback when search failsonSearchCanceled
: Callback when search is canceled
🔌 Adapters & Hooks
Import Paths
Each adapter is now available as a separate import:
// Core functionality
import { createSearchOptimizer } from 'search-optimizer';
// Fetch adapter
import { createFetchExecutor } from 'search-optimizer/adapters/fetch';
// Axios adapter
import { createAxiosExecutor } from 'search-optimizer/adapters/axios';
// GraphQL adapter
import { createGraphQLExecutor } from 'search-optimizer/adapters/graphql';
// Generic adapter for custom implementations
import { createGenericExecutor } from 'search-optimizer/adapters/generic';
// React hook
import { useSearchOptimizer } from 'search-optimizer/adapters/react';
Adapters
createFetchExecutor(options)
Creates a SearchExecutor using the Fetch API.
Options:
baseUrl
: Base URL for the search endpoint (required)queryParam
: Query parameter name for the search term (default: 'q')fetchOptions
: Additional fetch request optionsresponseTransformer
: Function to transform the fetch response
createAxiosExecutor(options)
Creates a SearchExecutor using Axios.
Options:
axios
: Axios instance to use for requests (required)baseUrl
: Base URL for the search endpoint (required)queryParam
: Query parameter name for the search term (default: 'q')axiosOptions
: Additional axios request options
createGraphQLExecutor(options)
Creates a SearchExecutor for GraphQL clients.
Options:
client
: GraphQL client instance (required)query
: GraphQL query document (required)queryVariableName
: Name of the variable to pass the search term (default: 'query')resultExtractor
: Function to extract search results from the GraphQL responseadditionalVariables
: Additional variables to include with every GraphQL request
createGenericExecutor(searchFn, options)
Creates a SearchExecutor using any custom search implementation.
Parameters:
searchFn
: Function that performs the search, with signature(query: string, signal?: AbortSignal) => Promise<T>
options
: Additional configuration optionsname
: Name for this custom executor (optional, useful for debugging)errorHandler
: Optional custom error handler function
Example:
// Create a custom executor with any search implementation
const myCustomExecutor = createGenericExecutor(
async (query, signal) => {
// Custom implementation using any API/library
const results = await customSearchLibrary.search(query, { signal });
return results.items;
},
{ name: 'CustomLibraryExecutor' },
);
// Use with SearchOptimizer
const searchOptimizer = createSearchOptimizer(myCustomExecutor);
Creating a Custom Adapter (Direct Implementation)
You can also implement the SearchExecutor
interface directly for complete control:
import { SearchExecutor, createSearchOptimizer } from 'search-optimizer';
// Implement the SearchExecutor interface directly
const myCustomExecutor: SearchExecutor = {
execute: async (query, signal) => {
// Your custom implementation here
// Full control over error handling, request formatting, etc.
const response = await fetch(`https://api.example.com/search?term=${query}`, {
headers: { 'Authorization': 'Bearer YOUR_API_KEY' },
signal
});
if (!response.ok) {
throw new Error(`Search failed: ${response.status}`);
}
const data = await response.json();
return data.results;
}
};
// Use with SearchOptimizer
const searchOptimizer = createSearchOptimizer(myCustomExecutor);
React Hook
useSearchOptimizer(executor, options)
React hook for using SearchOptimizer in functional components.
Returns:
query
: Current search query stringloading
: Boolean indicating if a search is in progressresults
: Search results (null if no search has been performed)error
: Error object (null if no error occurred)setQuery
: Function to update the search querysearch
: Function to manually trigger a searchcancel
: Function to cancel the current searchreset
: Function to reset the search stateinputProps
: Props object for easy React input element integration
🧪 Examples
Check out the examples directory for complete working demos:
- Basic React Example
- React Query Integration (Coming soon)
🤝 Contributing
We welcome contributions to SearchOptimizer! If you'd like to contribute, please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Please make sure to update tests as appropriate.
📝 Changelog
See the CHANGELOG.md file for details on version updates.
📄 License
This project is licensed under the MIT License. See the LICENSE file for details.