Hooks and the devtools object
useDevtoolsPanel, useDevtoolsWebView, useDevtoolsNavigation, and the module-level devtools object.
Four exports cover everything the provider does not: opening the panel, wiring a <WebView />,
handing over a navigation container, and the imperative calls.
useDevtoolsPanel()
Opens and closes the panel from your own UI, which is what makes showFloatingButton={false} usable
rather than a dead end.
import { useDevtoolsPanel } from '@axonpack/expo-devtools';
const panel = useDevtoolsPanel();| Member | What it is |
|---|---|
visible | Whether the panel is open right now. |
enabled | Whether the devtools are running. false with enabled: false, and then show does nothing. |
show() | Opens the panel. |
hide() | Closes it. |
toggle() | Either way. |
It reads the same state the launcher button does, so the two stay in step. Branch your own trigger on
enabled and a release build has no dead button in it.
useDevtoolsWebView(name)
Returns the props one <WebView /> needs to report in. See
In-app browsers for the whole story.
const devtoolsWebView = useDevtoolsWebView('checkout');
<WebView {...devtoolsWebView} source={{ uri }} />;source is the label the page's rows carry, defaulting to 'webview'. Any string works and it is only
a label: name each WebView when the app has more than one.
| Prop returned | What it does |
|---|---|
injectedJavaScriptBeforeContentLoaded | Patches fetch, XMLHttpRequest, WebSocket, EventSource and console in the page. |
onMessage | Receives what the page reports. Returns true when the message was one of ours. |
ref | Lets a conditions change reach an already-loaded page. |
userAgent | The current user-agent override, so the page identifies itself the way the panel says. |
onShouldStartLoadWithRequest | Blocks navigation while Offline is on. |
Everything it returns is inert until the devtools are running: the injected script is empty, and with no
onMessage behind it react-native-webview does not install the page bridge at all.
useDevtoolsNavigation(ref, name?)
Hands the Navigation tab a React Navigation container the provider cannot see: one mounted inside the provider. Call it from the component that owns the container. See Navigation for the whole story.
import { useDevtoolsNavigation } from '@axonpack/expo-devtools';
const navigationRef = createNavigationContainerRef();
function App() {
useDevtoolsNavigation(navigationRef);
return <NavigationContainer ref={navigationRef}>...</NavigationContainer>;
}| Argument | What it is |
|---|---|
ref | The container's ref, as createNavigationContainerRef() or Expo Router's useNavigationContainerRef() returns it. |
name | What the tab files this container's moves under. Defaults to 'root'. |
An Expo Router app needs no call, and neither does a provider mounted inside a container: both are found
on their own, under root. Name a second container, such as a checkout flow with its own, so the tab
can tell the two apart. Called from a screen of another container, the hook also learns which route it
sits in, and the tab draws this container under that route.
It is inert until the devtools are running, so the call is safe to leave in a release build.
devtools
A module-level object, for the things the panel cannot do for you.
import { devtools } from '@axonpack/expo-devtools';| Member | What it does |
|---|---|
mark(name, options?) | Records a user-timing mark. options: { detail?, startTime? }. |
measure(name, startOrOptions?, endMark?) | Records a measure. Second argument is a start-mark name or { start?, end?, duration?, detail? }. Passing start, end and duration together throws, since they can disagree. |
clearMarks(name?) | Drops recorded marks, all of them or one name. |
clearMeasures(name?) | Drops recorded measures, all of them or one name. |
setCrashContext(context) | Keys attached to every crash record from here on: user id, feature flags. Replaces rather than merges; null clears it. |
networkLogStore, networkConditionsStore, consoleLogStore, storageStore, navigationStore, crashStore | The underlying stores, if you want to read or drive them yourself. |
Nothing on it does anything until a provider has started with enabled: true, so call sites need no
guard of their own.
User timing
devtools.mark('checkout');
await buildCart();
devtools.measure('checkout'); // measures from the mark of the same namemeasure follows the W3C User Timing signatures, and calls are
forwarded to the real performance.mark and performance.measure too, so the entries exist on the
platform timeline as well. Nothing is observed from that timeline, which is why React's own internal
measures never appear in the list.