Axonpack
Reference

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();
MemberWhat it is
visibleWhether the panel is open right now.
enabledWhether 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 returnedWhat it does
injectedJavaScriptBeforeContentLoadedPatches fetch, XMLHttpRequest, WebSocket, EventSource and console in the page.
onMessageReceives what the page reports. Returns true when the message was one of ours.
refLets a conditions change reach an already-loaded page.
userAgentThe current user-agent override, so the page identifies itself the way the panel says.
onShouldStartLoadWithRequestBlocks 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>;
}
ArgumentWhat it is
refThe container's ref, as createNavigationContainerRef() or Expo Router's useNavigationContainerRef() returns it.
nameWhat 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';
MemberWhat 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, crashStoreThe 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 name

measure 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.

On this page