useFriendship
Location: src/hooks/useFriendship.js
Overview
Manages the complete friendship lifecycle between the current user and another user. Handles sending, canceling, accepting, declining friend requests, and removing existing friends. Integrates rate limiting for friend request spam prevention. Automatically reactivates canceled requests instead of creating duplicates.
Signature
function useFriendship(
otherUserId: string
): {
// State
loading: boolean,
error: string | null,
rateLimitError: string | null,
friendship: Friendship | null,
friendshipStatus: string | null,
isRequester: boolean,
isAddressee: boolean,
// Derived booleans
isFriend: boolean,
isPendingSent: boolean,
isPendingReceived: boolean,
hasNoRelationship: boolean,
// Actions
sendRequest: () => Promise<Result>,
cancelRequest: () => Promise<Result>,
acceptRequest: () => Promise<Result>,
declineRequest: () => Promise<Result>,
removeFriend: () => Promise<Result>,
refetch: () => Promise<void>,
clearError: () => void
}
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
otherUserId | string | Yes | The ID of the other user to manage friendship with |
Return Value
State
| Property | Type | Description |
|---|---|---|
loading | boolean | Whether a friendship operation is in progress |
error | string | null | Error message from the last failed operation |
rateLimitError | string | null | Rate limit error message (from useRateLimit) |
friendship | object | null | The raw friendship record from the database |
friendshipStatus | string | null | The friendship status: 'pending', 'accepted', 'declined', 'canceled', or null |
isRequester | boolean | Whether the current user sent the request |
isAddressee | boolean | Whether the current user received the request |
Derived Booleans
| Property | Type | Description |
|---|---|---|
isFriend | boolean | true if friendship status is 'accepted' |
isPendingSent | boolean | true if status is 'pending' and current user is the requester |
isPendingReceived | boolean | true if status is 'pending' and current user is the addressee |
hasNoRelationship | boolean | true if no friendship record exists |
Actions
| Property | Type | Description |
|---|---|---|
sendRequest | () => Promise<Result> | Send a friend request. Rate-limited. Returns { success: true } or { error, rateLimited? }. Reactivates canceled requests automatically. |
cancelRequest | () => Promise<Result> | Cancel a pending request (requester only). Sets status to 'canceled'. |
acceptRequest | () => Promise<Result> | Accept a pending request (addressee only). Sets status to 'accepted'. |
declineRequest | () => Promise<Result> | Decline a pending request (addressee only). Sets status to 'declined'. |
removeFriend | () => Promise<Result> | Remove an accepted friendship (either user). Deletes the record. |
refetch | () => Promise<void> | Re-fetch the friendship state from the database |
clearError | () => void | Clear error and rate limit error states |
Usage
import { useFriendship } from '../hooks/useFriendship';
function FriendButton({ userId }) {
const {
loading,
isFriend,
isPendingSent,
isPendingReceived,
hasNoRelationship,
sendRequest,
cancelRequest,
acceptRequest,
removeFriend
} = useFriendship(userId);
if (loading) return <span>Loading...</span>;
if (isFriend) {
return <button onClick={removeFriend}>Remove Friend</button>;
}
if (isPendingSent) {
return <button onClick={cancelRequest}>Cancel Request</button>;
}
if (isPendingReceived) {
return <button onClick={acceptRequest}>Accept Request</button>;
}
if (hasNoRelationship) {
return <button onClick={sendRequest}>Add Friend</button>;
}
return null;
}
Notes
- Friendship queries check both directions (
requester_id/addressee_id) and exclude declined/canceled records. - Rate limiting uses
RATE_LIMIT_ACTIONS.FRIEND_REQUESTfromuseRateLimit. - When sending a request to someone whose previous request was canceled, the hook reactivates the existing record instead of creating a duplicate.
Last updated: 2026-02-07