useUserLookup
Location: src/hooks/useUserLookup.js
Overview
Provides exact username lookup functionality. Searches for a single user by their exact username (no partial matching, no discovery). The lookup is performed via the lookup_user_by_username Supabase RPC function and includes rate limit detection.
Use this hook in friend-search or user-search UI components where exact username matching is required.
Signature
function useUserLookup(): {
lookup: (username: string) => Promise<object | null>,
isLoading: boolean,
error: string | null,
rateLimitError: boolean,
result: object | null,
reset: () => void
}
Parameters
This hook takes no parameters.
Return Value
| Property | Type | Description |
|---|---|---|
lookup | (username: string) => Promise<object | null> | Performs exact username lookup. Normalizes input to lowercase and validates format (a-z0-9_, 3-30 chars). Returns the user object or null. |
isLoading | boolean | Whether a lookup is currently in progress |
error | string | null | Error message if the lookup failed |
rateLimitError | boolean | Whether the lookup was rejected due to rate limiting |
result | object | null | The most recent lookup result (user object or null) |
reset | () => void | Clears result, error, and rate limit error state |
Usage
import { useUserLookup } from '../hooks/useUserLookup';
function UserSearch() {
const { lookup, isLoading, error, rateLimitError, result, reset } = useUserLookup();
const [username, setUsername] = useState('');
const handleSearch = async () => {
const user = await lookup(username);
if (user) {
console.log('Found user:', user.display_name);
}
};
return (
<div>
<input
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Enter exact username"
/>
<button onClick={handleSearch} disabled={isLoading}>
Search
</button>
{rateLimitError && <p>Too many searches. Please wait an hour.</p>}
{error && <p>{error}</p>}
{result && <UserCard user={result} />}
</div>
);
}
Notes
- Usernames are validated against the regex
/^[a-z0-9_]{3,30}$/before any database call. - If rate limited by the server, the hook sets
rateLimitErrortotrueand provides a user-friendly error message. - No partial matching or discovery is supported -- this is intentional for privacy (Invariant #14).
Last updated: 2026-02-07