Starting a DaVinci flow in React Native
PingOne React Native
The recommended way to start and navigate a DaVinci flow in a React Native component is with the useDaVinci hook. It returns an object containing the current node and a set of actions.
Use the start() action and pass a configured client to start a DaVinci flow:
const { node, start, loading, error } = useDaVinci(davinciClient);
useEffect(() => {
start().catch(() => {}); // error surfaced via hook state
}, [start]);
|
If you call Learn more in Sharing DaVinci state across screens. |
The hook stores the returned node and sets loading while start() or next() is running.
The error property contains the most recent hook-level error, or null when no hook error has occurred.
The auto-start effect catches the promise rejection because start() rejects when the flow cannot start.
The hook records the failure in its error state, so the catch block can remain empty.
Error handling
The start() action can reject when the module cannot configure or start the DaVinci flow.
The React Native module rejects failed operations with a DaVinciError, which extends PingError and ultimately extends the standard JavaScript Error class.
Use instanceof DaVinciError to identify the error and inspect its code, type, and message properties:
import { DaVinciError, useDaVinci } from '@ping-identity/rn-davinci';
import { Button} from 'react-native';
function LoginScreen() {
const { start } = useDaVinci(davinciClient);
async function beginFlow() {
try {
await start();
} catch (err) {
if (err instanceof DaVinciError) {
console.error(err.code, err.type, err.message);
}
}
}
return <Button title="Sign in" onPress={() => beginFlow()} />;
}
The stable error codes are:
| Error code | Description |
|---|---|
|
The app called an operation with an invalid argument. |
|
A collector value submitted with |
|
The client configuration is missing or invalid, such as an empty |
|
The native flow instance could not be disposed. |
|
The native DaVinci module could not initialize the flow. |
|
The user could not be signed out. |
|
A collector requires an integration, such as social sign-on, that the app has not configured. |
|
The flow could not advance to the next node. |
|
A polling operation could not be started. |
|
A session operation, such as refreshing or revoking tokens, failed. |
|
The flow could not be started. |
|
An operation was called in an invalid state, such as calling |
|
An unexpected error occurred. |
|
The app submitted a value for a collector whose type the bridge does not support, so no value can be applied to it. |
Sharing DaVinci state across screens
Each screen that calls useDaVinci(davinciClient) gets its own isolated hook state by default.
For example, a LoginScreen and an MfaScreen would each track their own node, loading, and error values rather than automatically sharing the current flow state.
The DaVinci module provides a DaVinciProvider that holds the configured client and shared hook state for descendant components.
Wrapping your navigator, or your entire app, with DaVinciProvider means that every screen within it can read and update the same flow state when it calls useDaVinci().
This is useful when a flow moves between screens, such as when a login screen collects credentials and a separate screen collects a multi-factor authentication code.
import {
DaVinciProvider,
useDaVinci,
} from '@ping-identity/rn-davinci';
const davinciClientConfig = {
modules: {
oidc: {
clientId: '6c7eb89a-66e9-ab12-cd34-eeaf795650b2',
discoveryEndpoint: 'https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration',
redirectUri: 'org.forgerock.demo://oauth2redirect',
},
},
};
function App(): React.ReactElement {
return (
<DaVinciProvider config={davinciClientConfig}>
<AuthNavigator />
</DaVinciProvider>
);
}
function LoginScreen(): React.ReactElement {
const { node, start, loading } = useDaVinci();
return <></>;
}
The provider creates one client from the supplied configuration and shares one hook state instance with its descendant components.
|
Calling |