# Location hooks

> **Info:** This is release candidate documentation for **Stream Chat React Native SDK v10**. For the latest stable version, see the [latest version (v9)](https://getstream.io/chat/docs/sdk/react-native/).

These hooks give a component the live location manager and follow the location shared in one message. They're exported from `stream-chat-react-native` and `stream-chat-expo`, with `LiveLocationManagerProvider`, the component that creates the manager.

Location sharing, and why live locations need a manager, is explained on [Location sharing](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/location-sharing/). The location being shared from the composer is in `locationComposer.state`: see [Composer hooks](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/composer-hooks/#composer-stores-without-a-hook).

Each 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.

## LiveLocationManagerProvider

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

```ts
LiveLocationManagerProvider(props: PropsWithChildren<{
  watchLocation: WatchLocation;
  getDeviceId?: () => string;
}>)
```

The props:

- `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 `react-native-<platform>-<user ID>`, such as `react-native-ios-cleo`.

It creates a `LiveLocationManager` for the client of `Chat`, starts it with `LiveLocationManager.init()`, and disposes of it when it unmounts. A new `watchLocation` or `getDeviceId` creates a new manager, so declare them at module scope. It needs `Chat` above it.

Render it once, around the part of the app that stays mounted while the user is signed in. Two managers would both send each position. The SampleApp wraps its navigator in it, with a `watchLocation` built on `@react-native-community/geolocation`:

```tsx
import type { PropsWithChildren } from "react";
import Geolocation from "@react-native-community/geolocation";
import type { WatchLocation } from "stream-chat";
import { LiveLocationManagerProvider } from "stream-chat-react-native";

const watchLocation: WatchLocation = (handler) => {
  const watchId = Geolocation.watchPosition(
    ({ coords }) =>
      handler({ latitude: coords.latitude, longitude: coords.longitude }),
    (error) => console.warn("Watching the location failed", error),
    { enableHighAccuracy: true },
  );
  return () => Geolocation.clearWatch(watchId);
};

export const LiveLocationRoot = ({ children }: PropsWithChildren) => (
  <LiveLocationManagerProvider watchLocation={watchLocation}>
    {children}
  </LiveLocationManagerProvider>
);
```

The app asks for location permission itself, before the user shares a live location.

## useLiveLocationManagerContext

Returns the live location manager.

```ts
useLiveLocationManagerContext(): { liveLocationManager: LiveLocationManager | null }
```

- **Returns:** `{ liveLocationManager }`, the manager `LiveLocationManagerProvider` created. `null` outside the provider.
- **Reads:** the context of `LiveLocationManagerProvider`. No store. The manager keeps its own state in `liveLocationManager.state`.
- **Re-renders:** when the provider renders, since it passes a new value each time.
- **Needs:** nothing. Never throws.

The manager's state holds two fields:

- `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`.

```tsx
import { Text } from "react-native";
import type { LiveLocationManagerState } from "stream-chat";
import {
  useLiveLocationManagerContext,
  useStateStore,
} from "stream-chat-react-native";

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

export const LiveLocationStatus = () => {
  const { liveLocationManager } = useLiveLocationManagerContext();
  const { messages } =
    useStateStore(liveLocationManager?.state, sharesSelector) ?? {};

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

## useHandleLiveLocationEvents

Follows the location shared in one message.

```ts
useHandleLiveLocationEvents(params: {
  channel: Channel;
  messageId: string;
  onLocationUpdate?: (location: SharedLocationResponse) => void;
}): {
  isLiveLocationStopped: boolean | null;
  locationResponse: SharedLocationResponse | undefined;
}
```

- **Returns:**
  - `locationResponse`: the message's `shared_location` from the latest `message.updated` event. `undefined` until the first one arrives, so start from `message.shared_location` and prefer this value once it's set.
  - `isLiveLocationStopped`: `true` once an update arrives whose `end_at` has passed. `null` before that. A live location that expires without a further update stays `null`, so compare `end_at` with the current time as well.
- **Reads:** the `message.updated` events of the channel for `messageId`. It calls `onLocationUpdate` with each new location.
- **Re-renders:** when an update for the message arrives.
- **Needs:** `Chat`. Throws outside it.

A new `onLocationUpdate` function subscribes again, so define it with `useCallback`. The SDK's components don't call this hook. The SampleApp's map screen uses it to move the marker of a live location.

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

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/location-hooks/](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/location-hooks/).