Poll hooks
These hooks give a component the poll it renders, and page through the poll's comments and votes. They're exported from stream-chat-react.
Polls are explained on Polls, and the poll components and PollContext 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.
usePollContext(): PollContextValue- Returns:
{ poll }: thePollof the nearestPollcomponent orPollProvider. - Reads: the context of
PollProvider, whichPollrenders. No store: the poll's data is inpoll.state, which you read withuseStateStore. - Re-renders: whenever the
PollProviderabove renders, since it passes a new value each time. Votes and other changes inpoll.statedon't re-render it by themselves. - Needs: a
Pollor aPollProvider. Throws outside both.
import type { PollState } from "stream-chat";
import { usePollContext, useStateStore } from "stream-chat-react";
const statusSelector = ({ is_closed, vote_count }: PollState) => ({
isClosed: is_closed,
voteCount: vote_count,
});
export const PollStatus = () => {
const { poll } = usePollContext();
const { isClosed, voteCount } = useStateStore(poll.state, statusSelector);
return (
<span>
{voteCount} votes{isClosed ? ", closed" : ""}
</span>
);
};The default MessageUI renders Poll for each message with a poll, so a component given to one of the poll override keys sits inside one. To render a poll's parts elsewhere, look the poll up with client.polls.fromState(pollId) and wrap them in <PollProvider poll={poll}>. PollProvider renders nothing while the poll is undefined.
usePollAnswerPagination
Loads the poll's comments, a page at a time.
usePollAnswerPagination(params?: { paginationParams?: PollAnswersQueryParams }): {
answers: PollVoteResponseData[];
error: Error | undefined;
hasNextPage: boolean;
loading: boolean;
loadMore: () => Promise<void>;
}paginationParams takes a filter, options such as limit, and a sort.
- Returns:
answers: the comments loaded so far, newest first. The hook sorts bycreated_at, newest first, before yoursort.loadMore(): loads the next page. It does nothing while a page is loading or after the last one.hasNextPageandloading: where the list stands.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. It loads the first page when it mounts. Thepoll.vote_casted,poll.vote_changedandpoll.vote_removedevents add, replace and remove comments after that. - Re-renders: when a page starts loading, loads or fails, and when a comment event arrives.
- Needs:
Chat, and aPollor aPollProvider. Throws outside them.
The list loads once. New paginationParams don't reload it: render the component again with a new key to start over. PollAnswerList, the View Comments dialog, uses this hook.
import { usePollAnswerPagination } from "stream-chat-react";
export const PollComments = () => {
const { answers, hasNextPage, loading, loadMore } = usePollAnswerPagination();
return (
<div>
<ul>
{answers.map((answer) => (
<li key={answer.id}>
{answer.user?.name}: {answer.answer_text}
</li>
))}
</ul>
{hasNextPage && (
<button
disabled={loading}
onClick={() => void loadMore()}
type="button"
>
More comments
</button>
)}
</div>
);
};usePollOptionVotesPagination
Loads the votes for one option, a page at a time.
usePollOptionVotesPagination(params: { paginationParams: PollOptionVotesQueryParams }): {
error: Error | undefined;
hasNextPage: boolean;
loading: boolean;
loadMore: () => Promise<void>;
votes: PollVoteResponseData[];
}paginationParams.filter.option_id names the option, and is required.
- Returns:
votes: the option's votes loaded so far, newest first, as forusePollAnswerPagination.loadMore(),hasNextPage,loadinganderror: as forusePollAnswerPagination.options.limitsets the size of the first page. Every page after it holds up to 5 votes.
- Reads:
Poll.queryOptionVotes(), into a list the hook keeps for the component. It loads the first page when it mounts, and follows the vote events for that option. - Re-renders: when a page starts loading, loads or fails, and when a vote for the option is cast, changed or removed.
- Needs:
Chat, and aPollor aPollProvider. Throws outside them.
Pass paginationParams with a stable identity, as PollResults does for each option:
import { useMemo } from "react";
import type { PollOptionVotesQueryParams } from "stream-chat";
import { usePollOptionVotesPagination } from "stream-chat-react";
export const OptionVoters = ({ optionId }: { optionId: string }) => {
const paginationParams = useMemo<PollOptionVotesQueryParams>(
() => ({ filter: { option_id: optionId } }),
[optionId],
);
const { hasNextPage, loadMore, votes } = usePollOptionVotesPagination({
paginationParams,
});
return (
<div>
{votes.map((vote) => (
<span key={vote.id}>{vote.user?.name}</span>
))}
{hasNextPage && (
<button onClick={() => void loadMore()} type="button">
Show more
</button>
)}
</div>
);
};Without useMemo, a first page that failed would be requested again on every render. A new optionId still doesn't reload the votes: where the option can change, render OptionVoters with key={optionId}.
Poll state without a hook
stream-chat-react has no hook for a poll's own state. Read poll.state with useStateStore, with the poll from usePollContext(), as PollStatus does above. It holds the poll's data and a few values derived from it:
| To read | Field in poll.state |
|---|---|
| The question and the options | name, options |
| The vote counts | vote_count, vote_counts_by_option |
| The leading options | maxVotedOptionIds |
| The current user's votes | ownVotesByOptionId |
| The current user's comment | ownAnswer |
| Whether voting has ended | is_closed |
Voting and keeping the poll current explains how votes and events change it. The poll being created in the composer is in pollComposer.state: see Composer hooks.