# Poll 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 poll it renders, read the poll's state, and page through the poll's comments and votes. They're exported from `stream-chat-react-native` and `stream-chat-expo`.

Polls are explained on [Polls](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/), and the poll components on [Poll components](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/poll-components/).

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.

## usePollContext

Returns the poll the component renders, and its message.

```ts
usePollContext(): PollContextValue
```

- **Returns:** `{ message, poll }`: the `Poll` from `stream-chat`, and the message that carries it.
- **Reads:** the context of `PollContextProvider`, which the `Poll` component renders, and the poll screens for all options, comments and results render again. No store. The poll's data is in `poll.state`.
- **Re-renders:** whenever the provider above renders, since `Poll` passes a new value each time. Votes and other changes in `poll.state` don't re-render it by themselves.
- **Needs:** a `Poll`, or a `PollContextProvider`. Throws outside both.

The default message renders `Poll` for each message with a poll, so a component you give to `WithComponents` as `PollContent`, `PollHeader` or `PollButtons` sits inside one. To render a poll's parts elsewhere, look the poll up with `client.polls.fromState(pollId)` and wrap them in `<PollContextProvider value={{ message, poll }}>`.

## usePollState

Returns the poll's state and the functions that change it.

```ts
usePollState(): UsePollStateReturnType
```

- **Returns:**
  - The poll's settings: `name`, `options`, `createdBy`, `enforceUniqueVote`, `maxVotesAllowed` (`0` when there's no limit), `allowAnswers`, `allowUserSuggestedOptions`, `votingVisibility` and `isClosed`.
  - Its votes: `voteCount`, `voteCountsByOption`, `latestVotesByOption`, `maxVotedOptionIds` (the leading options), `ownVotesByOptionId` and `answersCount`.
  - The current user's comment: `ownAnswer`.
  - `addOption(text)`: adds an option, with `Poll.createOption()`.
  - `addComment(text)`: adds the current user's comment, with `Poll.addAnswer()`, and returns the request's promise.
  - `endVote()`: closes the poll with `Poll.close()`, and publishes an `api:poll:end:success` or `api:poll:end:failed` notification. It rethrows when the request fails.
- **Reads:** `poll.state`, the poll from `usePollContext()`.
- **Re-renders:** when one of the returned state fields changes.
- **Needs:** `Chat`, and a `Poll` or a `PollContextProvider`. Throws outside them.

It reads every field at once. A component that shows one or two of them re-renders less with `usePollStateStore` and a selector of its own.

When `votingVisibility` is `'anonymous'`, the SDK's components don't show who voted or commented. `PollVote`, in the results, shows "Anonymous" and no avatar for every vote. `PollAnswerListItem` shows "Anonymous" for every comment but the user's own, which it finds by comparing the comment's `user.id` with the current user's. `PollOption` shows avatars only for the votes in `latestVotesByOption` that have a `user`. `user` is optional on a vote and on a comment, so a component of your own that shows voters should check `votingVisibility` as these do, and handle a vote without a `user`.

## usePollStateStore

Returns a selection of the poll's state.

```ts
usePollStateStore<T extends Readonly<Record<string, unknown> | Readonly<unknown[]>>>(
  selector: (state: PollState) => T,
): T
```

- **Returns:** what the selector returns.
- **Reads:** `poll.state`, through your selector, with the poll from `usePollContext()`.
- **Re-renders:** when a value in the selection changes. Define the selector at module scope.
- **Needs:** a `Poll` or a `PollContextProvider`. Throws outside both.

```tsx
import { Text } from "react-native";
import type { PollState } from "stream-chat";
import { usePollStateStore } from "stream-chat-react-native";

const statusSelector = ({ is_closed, vote_count }: PollState) => ({
  isClosed: is_closed,
  voteCount: vote_count,
});

export const PollStatus = () => {
  const { isClosed, voteCount } = usePollStateStore(statusSelector);

  return (
    <Text>
      {voteCount} votes{isClosed ? ", closed" : ""}
    </Text>
  );
};
```

## usePollAnswersPagination

Loads the poll's comments, a page at a time.

```ts
usePollAnswersPagination(params?: {
  loadFirstPage?: boolean;
  paginationParams?: PollAnswersQueryParams;
}): {
  error: Error | undefined;
  hasNextPage: boolean;
  loading: boolean;
  loadMore: () => void;
  next: string | null | undefined;
  pollAnswers: PollVoteResponseData[];
}
```

`paginationParams` takes a `filter`, `options` such as `limit`, and a `sort`. `loadFirstPage` is `true` by default.

- **Returns:**
  - `pollAnswers`: the comments loaded so far. The hook sorts by `updated_at`, newest first, before your `sort`.
  - `loadMore()`: loads the next page. It does nothing while a page is loading or after the last one.
  - `hasNextPage`, `loading` and `next`: where the list stands. `next` is the cursor of the next page.
  - `error`: the error of the last request that failed. A page that loads after it doesn't clear it.
- **Reads:** `Poll.queryAnswers()`, into a list the hook keeps for the component. With `loadFirstPage`, it loads the first page when it mounts. The `poll.vote_casted` and `poll.vote_changed` events for the poll add or replace a comment, and `poll.vote_removed` removes one.
- **Re-renders:** when a page starts loading, loads or fails, and when a comment event arrives.
- **Needs:** `Chat`, and a `Poll` or a `PollContextProvider`. Throws outside them.

Pass `paginationParams` with a stable identity. While the list is empty, a new identity requests the first page again, so a first page that failed is requested on every render. New `paginationParams` don't reload a list that has comments: render the component again with a new `key` to start over. `PollAnswersList`, the comments screen, uses this hook.

```tsx
import { FlatList, Text } from "react-native";
import type { PollVoteResponseData } from "stream-chat";
import { usePollAnswersPagination } from "stream-chat-react-native";

const renderItem = ({ item }: { item: PollVoteResponseData }) => (
  <Text>
    {item.user?.name}: {item.answer_text}
  </Text>
);

export const PollComments = () => {
  const { loadMore, pollAnswers } = usePollAnswersPagination();

  return (
    <FlatList
      data={pollAnswers}
      keyExtractor={(item) => item.id}
      onEndReached={loadMore}
      renderItem={renderItem}
    />
  );
};
```

## usePollOptionVotesPagination

Loads the votes for one option, a page at a time.

```ts
usePollOptionVotesPagination(params: {
  option: PollOptionResponseData;
  loadFirstPage?: boolean;
  paginationParams?: PollOptionVotesQueryParams;
}): {
  error: Error | undefined;
  hasNextPage: boolean;
  loading: boolean;
  loadMore: () => void;
  next: string | null | undefined;
  votes: PollVoteResponseData[];
}
```

`option` is the option whose votes to load, one of the poll's `options`. Its `id` is added to the query's filter.

- **Returns:**
  - `votes`: the option's votes loaded so far. The hook sorts by `created_at`, newest first, before your `sort`.
  - `loadMore()`, `hasNextPage`, `loading`, `next` and `error`: as for `usePollAnswersPagination`.
- **Reads:** `Poll.queryOptionVotes()`, into a list the hook keeps for the component. With `loadFirstPage`, it loads the first page when it mounts. It follows the vote events of the poll: a vote cast or changed for the option is added or replaced, a vote changed to another option is removed, and a removed vote is removed.
- **Re-renders:** when a page starts loading, loads or fails, and when a vote event for the option arrives.
- **Needs:** `Chat`, and a `Poll` or a `PollContextProvider`. Throws outside them.

Pass `paginationParams` with a stable identity, as for `usePollAnswersPagination`. A new `option` with another `id` doesn't reload votes that have loaded: render the component with `key={option.id}`. `PollOptionFullResults`, the screen with every vote of an option, uses this hook.

## useCreatePollContentContext

Returns what the poll creation screen provides to its parts.

```ts
useCreatePollContentContext(): CreatePollContentContextValue
```

- **Returns:**
  - `createAndSendPoll()`: creates the poll from the composer's poll form with `MessageComposer.createPoll()`, sends the message, and closes the screen. It logs an error instead of throwing.
  - `sendMessage()`: the composer's `sendMessage`.
  - `closePollCreationDialog()`: closes the screen.
  - `createPollOptionGap`: the space between the options in the form.
  - `modalStateStore`: a store with `isClosing`, `true` while the screen animates away.
- **Reads:** the context `CreatePoll` provides around `CreatePollContent`. No store.
- **Re-renders:** whenever `CreatePoll` renders, since it passes a new value each time.
- **Needs:** `CreatePoll`, which `MessageComposer` renders when the user opens the poll form. Throws outside it. Use it in a component you give to `WithComponents` as `CreatePollContent`.

The poll being created lives in the composer, in `pollComposer.state`: read it with `useStateStore` and the composer from [`useMessageComposer()`](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/composer-hooks/#usemessagecomposer). [Polls](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/) shows a creation screen of your own.

## Poll state fields

`usePollState` renames the fields of `poll.state`. With `usePollStateStore` or `useStateStore`, select them by their names in `PollState`:

| To read                      | Field in `poll.state`                 |
| ---------------------------- | ------------------------------------- |
| The question and the options | `name`, `options`                     |
| The vote counts              | `vote_count`, `vote_counts_by_option` |
| The latest votes per option  | `latest_votes_by_option`              |
| The leading options          | `maxVotedOptionIds`                   |
| The current user's votes     | `ownVotesByOptionId`                  |
| The comments                 | `answers_count`, `latest_answers`     |
| The current user's comment   | `ownAnswer`                           |
| Whether voting has ended     | `is_closed`                           |

[Polls](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/) explains how votes and events change them.

---

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