Split useFriends into state + actions via useBetween singleton

useFriends backs ~16 consumers with a friend-list state (5 useStates +
6 message-event listeners) plus 4 imperative entry points
(requestFriend, requestResponse, followFriend, updateRelationship).
Same singleton-filter pattern as useNotification / useWiredTools /
useTranslation.

- useFriendsStore (internal, was useFriendsState) — the previous body
  untouched.
- useFriendsState (public, read-only) — friends arrays, settings,
  derived onlineFriends / offlineFriends, getFriend lookup,
  canRequestFriend guard, plus setDismissedRequestIds (UI-local 'hide
  banner' state).
- useFriendsActions (public, imperative) — requestFriend,
  requestResponse, followFriend, updateRelationship.
- useFriends (deprecated shim) — composes both, preserving the
  historical full-shape return.
This commit is contained in:
simoleo89
2026-05-11 23:00:39 +02:00
parent 5344eaf5c0
commit 9f3cd9bd46
+76 -2
View File
@@ -5,7 +5,14 @@ import { CloneObject, LocalizeText, MessengerFriend, MessengerRequest, Messenger
import { useMessageEvent } from '../events';
import { useNotification } from '../notification';
const useFriendsState = () =>
/**
* Internal singleton store for friend-list state + actions. Public
* consumers should use useFriendsState (read-only — friends arrays,
* settings, derived online/offline split) or useFriendsActions
* (imperative — request / response / follow / update). useFriends is
* the legacy shim that composes both.
*/
const useFriendsStore = () =>
{
const [ friends, setFriends ] = useState<MessengerFriend[]>([]);
const [ requests, setRequests ] = useState<MessengerRequest[]>([]);
@@ -255,4 +262,71 @@ const useFriendsState = () =>
return { friends, requests, sentRequests, dismissedRequestIds, setDismissedRequestIds, settings, onlineFriends, offlineFriends, getFriend, canRequestFriend, requestFriend, requestResponse, followFriend, updateRelationship };
};
export const useFriends = () => useBetween(useFriendsState);
/**
* Read-only slice of the friends store: the friend list itself
* (friends, requests, sentRequests, dismissedRequestIds, settings)
* plus the derived online/offline splits and the lookup helpers
* (getFriend, canRequestFriend) that don't mutate state.
*
* setDismissedRequestIds is exposed here because most consumers that
* read dismissedRequestIds also need to mutate it (it's UI-local
* "I've already hidden this banner" state, not server-driven).
*/
export const useFriendsState = () =>
{
const {
friends,
requests,
sentRequests,
dismissedRequestIds,
setDismissedRequestIds,
settings,
onlineFriends,
offlineFriends,
getFriend,
canRequestFriend
} = useBetween(useFriendsStore);
return {
friends,
requests,
sentRequests,
dismissedRequestIds,
setDismissedRequestIds,
settings,
onlineFriends,
offlineFriends,
getFriend,
canRequestFriend
};
};
/**
* Imperative slice of the friends store: request a new friendship,
* respond to an incoming request, follow a friend, update an existing
* relationship.
*/
export const useFriendsActions = () =>
{
const {
requestFriend,
requestResponse,
followFriend,
updateRelationship
} = useBetween(useFriendsStore);
return {
requestFriend,
requestResponse,
followFriend,
updateRelationship
};
};
/**
* @deprecated Prefer `useFriendsState` (read-only friends list) and
* `useFriendsActions` (request / follow / update) directly. This shim
* composes both into the historical `useFriends()` shape so the 16
* existing consumers keep working unchanged.
*/
export const useFriends = () => useBetween(useFriendsStore);