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 }: thePollfromstream-chat, and the message that carries it. - Reads: the context of
PollContextProvider, which thePollcomponent renders, and the poll screens for all options, comments and results render again. No store. The poll's data is inpoll.state. - Re-renders: whenever the provider above renders, since
Pollpasses a new value each time. Votes and other changes inpoll.statedon't re-render it by themselves. - Needs: a
Poll, or aPollContextProvider. 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(0when there's no limit),allowAnswers,allowUserSuggestedOptions,votingVisibilityandisClosed. - Its votes:
voteCount,voteCountsByOption,latestVotesByOption,maxVotedOptionIds(the leading options),ownVotesByOptionIdandanswersCount. - The current user's comment:
ownAnswer. addOption(text): adds an option, withPoll.createOption().addComment(text): adds the current user's comment, withPoll.addAnswer(), and returns the request's promise.endVote(): closes the poll withPoll.close(), and publishes anapi:poll:end:successorapi:poll:end:failednotification. It rethrows when the request fails.
- The poll's settings:
- Reads:
poll.state, the poll fromusePollContext(). - Re-renders: when one of the returned state fields changes.
- Needs:
Chat, and aPollor aPollContextProvider. 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 fromusePollContext(). - Re-renders: when a value in the selection changes. Define the selector at module scope.
- Needs: a
Pollor aPollContextProvider. 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 byupdated_at, newest first, before yoursort.loadMore(): loads the next page. It does nothing while a page is loading or after the last one.hasNextPage,loadingandnext: where the list stands.nextis 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. WithloadFirstPage, it loads the first page when it mounts. Thepoll.vote_castedandpoll.vote_changedevents for the poll add or replace a comment, andpoll.vote_removedremoves one. - Re-renders: when a page starts loading, loads or fails, and when a comment event arrives.
- Needs:
Chat, and aPollor aPollContextProvider. 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 bycreated_at, newest first, before yoursort.loadMore(),hasNextPage,loading,nextanderror: as forusePollAnswersPagination.
- Reads:
Poll.queryOptionVotes(), into a list the hook keeps for the component. WithloadFirstPage, 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 aPollor aPollContextProvider. 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 withMessageComposer.createPoll(), sends the message, and closes the screen. It logs an error instead of throwing.sendMessage(): the composer'ssendMessage.closePollCreationDialog(): closes the screen.createPollOptionGap: the space between the options in the form.modalStateStore: a store withisClosing,truewhile the screen animates away.
- Reads: the context
CreatePollprovides aroundCreatePollContent. No store. - Re-renders: whenever
CreatePollrenders, since it passes a new value each time. - Needs:
CreatePoll, whichMessageComposerrenders when the user opens the poll form. Throws outside it. Use it in a component you give toWithComponentsasCreatePollContent.
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.