Info:
This is release candidate documentation for Stream Chat React Native SDK v10. For the latest stable version, see the latest version (v9).

Poll hooks

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, and the poll components on 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.

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.

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.

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

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.

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.

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.

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(). 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 explains how votes and events change them.