# Messages

A channel's messages live in `channel.messagePaginator`, pinned messages in `channel.pinnedMessagesPaginator`, and a thread's replies in `thread.messagePaginator`. Every loaded message, reply included, is also in `client.messageStore`.

## Reading

```js label="JavaScript"
// Messages on screen, loading and pagination flags
const { items, isLoading, hasMoreTail } =
  channel.messagePaginator.state.getLatestValue();

// Latest message of the channel
const lastMessage = channel.messagePaginator.latestMessage;

// Any loaded message by id
const message = client.messageStore.get(messageId);

// Did it send? "sending", "received" or "failed"
console.log(message?.status);

// Pinned messages
const { items: pinnedMessages } =
  channel.pinnedMessagesPaginator.state.getLatestValue();
```

Subscribe to render changes:

```js label="JavaScript"
const unsubscribe = channel.messagePaginator.state.subscribeWithSelector(
  (state) => ({ items: state.items }),
  ({ items }) => renderMessages(items),
);

// The latest message is reactive through `aggregateState`
const unsubscribeLastMessage =
  channel.messagePaginator.aggregateState.subscribeWithSelector(
    (state) => ({ latestMessage: state.latestMessage }),
    ({ latestMessage }) => renderPreview(latestMessage),
  );
```

## Loading older messages

`toTail()` loads the next page of older messages into `items`. `hasMoreTail` tells you whether there are more to load.

```js label="JavaScript"
const { hasMoreTail } = channel.messagePaginator.state.getLatestValue();

if (hasMoreTail) {
  await channel.messagePaginator.toTail();
}
```

## Jumping to a message

After a jump, `items` is the window around the target. `messageFocusSignal` tells you where to scroll.

```js label="JavaScript"
await channel.messagePaginator.jumpToMessage(messageId);

const { signal } = channel.messagePaginator.messageFocusSignal.getLatestValue();
scrollToMessage(signal?.messageId);
```

## Thread replies

A thread's replies are in `thread.messagePaginator`, the same paginator as a channel's messages, so everything on this page works for replies too. See [Thread](https://getstream.io/chat/docs/javascript/state-thread/) for how to get a thread.

```js label="JavaScript"
// Replies on screen, loading and pagination flags
const {
  items: replies,
  isLoading,
  hasMoreTail,
} = thread.messagePaginator.state.getLatestValue();

// Load older replies
if (hasMoreTail) {
  await thread.messagePaginator.toTail();
}

// Jump to a reply
await thread.messagePaginator.jumpToMessage(replyId);
```

## Configure the query

For message lists you can configure the page size. By default, a page is 100 messages in a channel, 50 replies in a thread and 100 pinned messages. Set it in the client configuration, before you load channels and threads.

```js label="JavaScript"
client.config.set({
  // Every channel message list and thread reply list
  messagePaginator: { pageSize: 50 },
  // Overrides for thread replies and pinned messages
  thread: { messagePaginator: { pageSize: 25 } },
  channel: { pinnedMessagesPaginator: { pageSize: 20 } },
});
```

The first page that `channel.watch()` loads has the same size.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/javascript/state-messages/](https://getstream.io/chat/docs/javascript/state-messages/).