# React Hooks
Incorporate Spaces into your React application with idiomatic and user-friendly React Hooks.
This package enables you to:
* Interact with Ably [Spaces](https://ably.com/docs/spaces.md) using a React Hook
* Subscribe to [events](https://ably.com/docs/spaces/avatar.md#events) in a space
* Retrieve the [membership](https://ably.com/docs/spaces/space.md) of a space
* Set the [location](https://ably.com/docs/spaces/locations.md) of space members
* Acquire [locks](https://ably.com/docs/spaces/locking.md) on components within a space
* Set the position of [members' cursors](https://ably.com/docs/spaces/cursors.md) in a space
The following hooks are available:
| Hook | Description |
| ---- | ----------- |
| [`useSpace`](#useSpace) | The `useSpace` hook lets you subscribe to the current Space, receive Space state events, and get the current Space instance. |
| [`useMembers`](#useMembers) | The `useMembers` hook is useful in building avatar stacks. Using `useMembers`, you can retrieve space members. |
| [`useLocations`](#useLocations) | The `useLocations` hook lets you subscribe to location events. Location events are emitted whenever a member changes location. |
| [`useLocks`](#useLocks) | The `useLocks` hook lets you subscribe to lock events by registering a listener. Lock events are emitted whenever the lock state transitions into `locked` or `unlocked`. |
| [`useLock`](#useLock) | The `useLock` hook returns the status of a lock and, if it has been acquired, the member holding the lock. |
| [`useCursors`](#useCursors) | The `useCursors` hook allows you to track a member's pointer position updates across an application. |
Spaces hooks are client-side oriented. If you employ server-side rendering, ensure components using these hooks render only on the client-side.
## Install
```shell
npm install ably @ably/spaces
```
## Authenticate
An [API key](https://ably.com/docs/auth.md#api-keys) is required to authenticate with Ably. API keys are used either to authenticate directly with Ably using [basic authentication](https://ably.com/docs/auth/basic.md), or to generate tokens for untrusted clients using [token authentication](https://ably.com/docs/auth/token.md).
[Sign up](https://ably.com/sign-up) to Ably to create an API key in the [dashboard](https://ably.com/dashboard) or use the [Control API](https://ably.com/docs/platform/account/control-api.md) to create an API programmatically.
## Usage
### Setting up the Spaces Provider
Use the `SpacesProvider` component to connect to Ably. The `SpacesProvider` should wrap every component that needs to access Spaces.
```react
import { Realtime } from "ably";
import Spaces from "@ably/spaces";
import { SpacesProvider, SpaceProvider } from "@ably/spaces/react";
const ably = new Realtime({ key: "your-api-key", clientId: 'clemons' });
const spaces = new Spaces(ably);
root.render(
)
```
### useSpace
The `useSpace` hook enables you to subscribe to the current [Space](https://ably.com/docs/spaces/space.md), receive Space state events, and get the current Space instance.
```react
const { space } = useSpace((update) => {
console.log(update);
});
```
### useMembers
`useMembers` is used to build [avatar stacks](https://ably.com/docs/spaces/avatar.md). It retrieves members of the space, including members that have recently left the space, but have not yet been removed.
```react
const { self, others, members } = useMembers();
```
- `self` - a member’s own member object
- `others` - an array of member objects for all members other than the member themselves
- `members` - an array of all member objects, including the member themselves
`useMembers` also enables you to subscribe to members entering, leaving, and being removed from the Space (after a timeout), as well as when a member updates their [profile information](https://ably.com/docs/spaces/space.md#update-profile).
```react
// Subscribe to all member events in a space
useMembers((memberUpdate) => {
console.log(memberUpdate);
});
// Subscribe to member enter events only
useMembers('enter', (memberJoined) => {
console.log(memberJoined);
});
// Subscribe to member leave events only
useMembers('leave', (memberLeft) => {
console.log(memberLeft);
});
// Subscribe to member remove events only
useMembers('remove', (memberRemoved) => {
console.log(memberRemoved);
});
// Subscribe to profile updates on members only
useMembers('updateProfile', (memberProfileUpdated) => {
console.log(memberProfileUpdated);
});
// Subscribe to all updates to members
useMembers('update', (memberUpdate) => {
console.log(memberUpdate);
});
```
### useLocations
`useLocations` enables you to subscribe to [location](https://ably.com/docs/spaces/locations.md) events. Location events are emitted whenever a member changes location.
```react
useLocations((locationUpdate) => {
console.log(locationUpdate);
});
```
`useLocations` also enables you to update the current member location using the `update` method provided by the hook. For example:
```react
const { update } = useLocations((locationUpdate) => {
console.log(locationUpdate);
});
```
### useLocks
`useLocks` enables you to subscribe to [lock](https://ably.com/docs/spaces/locking.md) events by registering a listener. Lock events are emitted whenever a lock transitions into the `locked` or `unlocked` state.
```react
useLocks((lockUpdate) => {
console.log(lockUpdate);
});
```
### useLock
`useLock` returns the status of a [lock](https://ably.com/docs/spaces/locking.md) and, if the lock has been acquired, the member holding that lock.
```react
const { status, member } = useLock('my-lock');
```
### useCursors
`useCursors` enables you to track a member's [cursor](https://ably.com/docs/spaces/cursors.md) position and provide a view of all members' cursors within a space. For example:
```react
// Subscribe to events published on "mousemove" by all members
const { set } = useCursors((cursorUpdate) => {
console.log(cursorUpdate);
});
useEffect(() => {
// Publish a your cursor position on "mousemove" including optional data
const eventListener = ({ clientX, clientY }) => {
set({ position: { x: clientX, y: clientY }, data: { color: 'red' } });
}
window.addEventListener('mousemove', eventListener);
return () => {
window.removeEventListener('mousemove', eventListener);
};
});
```
If you provide `{ returnCursors: true }` as an option you can retrieve active members' cursors:
```react
const { cursors } = useCursors((cursorUpdate) => {
console.log(cursorUpdate);
}, { returnCursors: true });
```
### Error handling
[`useSpace`](#useSpace), [`useMembers`](#useMembers), [`useLocks`](#useLocks), and [`useCursors`](#useCursors) return [connection](https://ably.com/docs/connect.md) and [channel](https://ably.com/docs/channels.md) errors you may encounter, so that you can handle them within your components. This may include when a client doesn't have permission to attach to a channel, or if it loses its connection to Ably.
```react
const { connectionError, channelError } = useMembers();
if (connectionError) {
// TODO: handle connection errors
} else if (channelError) {
// TODO: handle channel errors
} else {
return
}
```