---
title: Handling polling collectors in React Native
description: Monitor POLLING collectors and handle terminal statuses in a React Native DaVinci flow.
component: orchsdks
page_id: orchsdks:davinci:usage/react-native/collectors/polling
canonical_url: https://developer.pingidentity.com/orchsdks/davinci/usage/react-native/collectors/polling.html
llms_txt: https://developer.pingidentity.com/orchsdks/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: Fri, 28 Aug 2026 00:00:00 +0000
keywords: ["DaVinci", "React Native", "PollingCollector", "POLLING", "pollStatus"]
section_ids:
  monitoring_polling_status: Monitoring polling status
  continuing_after_polling: Continuing after polling
---

# Handling polling collectors in React Native

[icon: circle-check, set=far]PingOne [icon: react, set=fab]React Native

* [Prepare](../01-configuring-the-server.html)

* [Install](../02-installing-the-davinci-module.html)

* [Configure](../03-configuring-the-davinci-module.html)

* [Start](../04-starting-a-davinci-flow.html)

* **Navigate**

* [Manage](../06-handling-sessions.html)

A DaVinci flow can use polling when the user must complete an action outside the current screen. For example, a user might approve a request on another device, scan a QR code, or complete an out-of-band verification step. The app can show progress while it waits for the server to report the result.

The React Native bridge exposes this state as a `POLLING` collector and provides the `pollStatus()` action for monitoring it. Polling is output-only: it does not provide a value for ordinary form submission.

## Monitoring polling status

The `pollStatus()` action reports an intermediate `continue` status and one terminal status: `complete`, `timedOut`, `expired`, or `error`. The callback receives the exact status object from the bridge.

The following example keeps the latest status in React state, advances the flow when a terminal status arrives, and removes the local listener when the component unmounts:

Monitor a polling collector

```typescript
import { useEffect, useState } from 'react';
import { Text } from 'react-native';
import { useDaVinci } from '@ping-identity/rn-davinci';
import type { PollingStatus } from '@ping-identity/rn-davinci';

function PollingField({ collectorKey }) {
  const { node, pollStatus, next } = useDaVinci(davinciClient);
  const [status, setStatus] = useState<PollingStatus | null>(null);

  useEffect(() => {
    if (node?.type !== 'ContinueNode') return;

    let unsubscribe: (() => void) | undefined;
    let active = true;

    setStatus(null);

    void pollStatus(
      nextStatus => {
        if (active) setStatus(nextStatus);

        if (nextStatus.status !== 'continue') {
          next({ collectors: [] }).catch(() => {
            // next() records the failure in the hook's `error` state.
          });
        }
      },
      { key: collectorKey },
    )
      .then(removeListener => {
        if (active) {
          unsubscribe = removeListener;
        } else {
          removeListener();
        }
      })
      .catch(() => {
        // pollStatus() rejects when the node has no polling collector.
        // This rejection is not recorded in the hook's `error` state.
      });

    return () => {
      active = false;
      unsubscribe?.();
    };
  }, [collectorKey, node, pollStatus, next]);

  if (!status || status.status === 'continue') {
    const progress =
      status?.status === 'continue'
        ? ` (${status.retryCount}/${status.maxRetries})`
        : '';
    return <Text>Waiting for approval{progress}…</Text>;
  }

  if (status.status === 'complete') {
    return <Text>Approval complete.</Text>;
  }

  if (status.status === 'timedOut') {
    return <Text>The approval timed out.</Text>;
  }

  if (status.status === 'expired') {
    return <Text>The approval expired.</Text>;
  }

  return <Text>Polling failed: {status.error.message}</Text>;
}
```

When multiple polling collectors exist, pass the required collector key in the `key` option. If you omit the option, the SDK monitors the first polling collector on the active node.

When the node has no polling collector, `pollStatus()` rejects. Handle the rejection in your app, for example by logging it or displaying a message. The hook does not record this rejection in its `error` state, because `pollStatus()` returns its result as a `Promise` rather than through shared hook state.

## Continuing after polling

`pollStatus()` does not call `next()` automatically. After a terminal status, decide how your app should continue and submit the active `ContinueNode` explicitly, for example with `next({ collectors: [] })` when the flow expects no additional values.

The example in the previous section calls `next({ collectors: [] })` as soon as the terminal status arrives. If your flow requires additional values after polling, submit them instead.

The terminal status ends event delivery for that polling subscription. The returned unsubscribe function stops local JavaScript delivery only; it does not cancel the native poll. Native polling continues until it completes or reaches its configured timeout and retry limit.

If the app leaves the screen, call the unsubscribe function to stop updating that screen. Do not treat that function as a native cancellation API.

See [Stepping through DaVinci flows](../05-stepping-through-davinci-flows.html) for the common node and submission model.
