Location hooks

This hook keeps the current user's live locations updated. It's exported from stream-chat-react.

Location sharing, and why live locations need this hook, is explained on Location sharing. The location being shared from the composer is in locationComposer.state: see Composer hooks.

The entry gives the signature, then:

  • Returns: what the hook gives back.
  • Reads: the store or the context it reads.
  • Re-renders: what makes the component render again.
  • Needs: where the component must sit, and what the hook does outside that place.

useLiveLocationSharingManager

Creates the manager that sends the user's position to every live location they're sharing.

useLiveLocationSharingManager(params: {
  client?: StreamChat | null;
  getDeviceId?: () => string;
  watchLocation: WatchLocation;
}): LiveLocationManager | null

The params:

  • client: the client whose user shares the locations.

  • watchLocation: (handler) => unsubscribe. It starts watching the device's position and calls handler with each { latitude, longitude }. The manager calls it while at least one live share is active, and calls the returned function when none is left.

  • getDeviceId: the id of the device the shares come from. By default it's built from the device type, the browser and the user id, such as web-desktop-chrome-ann.

  • Returns: a LiveLocationManager, or null while client is null or undefined. The hook starts it with LiveLocationManager.init() and stops it when the component unmounts or the hook creates another one.

  • Reads: no store and no context. The manager keeps its own state in manager.state.

  • Re-renders: never by itself. A new client, getDeviceId or watchLocation creates a new manager, so declare the functions at module scope or with useCallback.

  • Needs: nothing: it takes the client as a param and works outside Chat. The client must have a connected user, or creating the manager throws. useCreateChatClient returns null until the user is connected, so its result can be passed as it is.

Call it once, in a component that stays mounted while the user is signed in. Two managers would both send each position. This one also shows how many live locations are active:

import type { LiveLocationManagerState, WatchLocation } from "stream-chat";
import {
  useChatContext,
  useLiveLocationSharingManager,
  useStateStore,
} from "stream-chat-react";

const watchLocation: WatchLocation = (handler) => {
  const watchId = navigator.geolocation.watchPosition((position) => {
    handler({
      latitude: position.coords.latitude,
      longitude: position.coords.longitude,
    });
  });
  return () => navigator.geolocation.clearWatch(watchId);
};

const sharesSelector = ({ messages }: LiveLocationManagerState) => ({
  messages,
});

export const LiveLocationStatus = () => {
  const { client } = useChatContext();
  const manager = useLiveLocationSharingManager({ client, watchLocation });
  const { messages } = useStateStore(manager?.state, sharesSelector) ?? {};

  if (!messages?.size) return null;
  return <span>Sharing your live location in {messages.size} messages</span>;
};

Live location state without a hook

stream-chat-react has no hook for the manager's state. Read manager.state with useStateStore, as LiveLocationStatus does:

  • ready: whether the manager has loaded the user's active live locations.
  • messages: a Map from message id to each live location the user is sharing, with its end_at.

A location shown in a message is message.shared_location, and changes with the message's message.updated event.