-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
🏝️ TanStack Query DevTools for Expo/React Native! 🚀 #8846
base: main
Are you sure you want to change the base?
Conversation
View your CI Pipeline Execution ↗ for commit 3aba238.
☁️ Nx Cloud last updated this comment at |
@@ -133,6 +133,38 @@ interface ContinueAction { | |||
type: 'continue' | |||
} | |||
|
|||
export interface RefetchActionEvent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think these should be here. The actions listened on the NotifyEvents are events that are dispatched from our query reducer. Consumers can listen to those to observe updates that happen in the cache. When the devtools trigger an update that will result in an internal state change, those changes will automatically be propagated.
Can you explain why those were added?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any other ideas to capture action events that's reliable? I added these, so I know exactly what action is pressed to forward the action to mobile. it just seemed like the easiest approach to subscribe to query events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I don’t understand what you’re trying to do. Why do you need to capture an event that happens in the devtools? Capture it where?
Assume I understand nothing about react native and expo (which is 99% true) and try to break down for me what you’re doing. If you want to listen to events from the devtools, doing that by dispatching an event on the queryCache and then listening to that is pretty likely not the right approach
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My plugin includes a web view that runs the React Query DevTools. The challenge I’m facing is linking DevTools actions to another client—in this case, mobile. I need to know when actions like refetch, invalidate, or set online/offline are triggered inside the DevTools UI.
Right now, the web view listens for those actions and sends a message to the mobile client to trigger the same action there. This works for all DevTools actions and online state changes.
If there's a simpler way to detect which action was pressed—along with the associated query and action type—I’d be happy to update the approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so should we make the devtools emit those events and you’d directly listen to those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 🌐 Web Client (DevTools in WebView) — Listening for Query Actions
// Subscribe to query changes
`const querySubscription = queryClient.getQueryCache().subscribe((event) => {
switch (event.type) {
case "updated":
switch (event.action.type as QueryActions) {
case "ACTION-REFETCH":
case "ACTION-INVALIDATE":
case "ACTION-TRIGGER-ERROR":
case "ACTION-RESTORE-ERROR":
case "ACTION-RESET":
case "ACTION-REMOVE":
case "ACTION-TRIGGER-LOADING":
case "ACTION-RESTORE-LOADING":
client.sendMessage("query-action", {
queryHash: event.query.queryHash,
queryKey: event.query.queryKey,
action: event.action.type as QueryActions,
targetDevice: selectedDeviceRef.current,
} as QueryActionMessage);
break;
case "success":
// @ts-ignore
if (event.action.manual) {
client.sendMessage("query-action", {
queryHash: event.query.queryHash,
queryKey: event.query.queryKey,
data: event.query.state.data,
action: "ACTION-DATA-UPDATE",
targetDevice: selectedDeviceRef.current,
} as QueryActionMessage);
}
break;
}
}
});
// 📱 Mobile Client — Handling Incoming Actions from Web DevTools
// Query Actions handler - Update query data, trigger errors, etc.
`const queryActionSubscription = client.addMessageListener(
"query-action",
(message: QueryActionMessage) => {
const { queryHash, queryKey, data, action, targetDevice } = message;
if (!shouldProcessMessage(targetDevice, Device.deviceName || "")) {
return;
}
const activeQuery = queryClient.getQueryCache().get(queryHash);
if (!activeQuery) {
console.warn(`Query with hash ${queryHash} not found`);
return;
}
switch (action) {
case "ACTION-DATA-UPDATE": {
queryClient.setQueryData(queryKey, data, {
updatedAt: Date.now(),
});
break;
}
case "ACTION-TRIGGER-ERROR": {
const error = new Error("Unknown error from devtools");
const __previousQueryOptions = activeQuery.options;
activeQuery.setState({
status: "error",
error,
fetchMeta: {
...activeQuery.state.fetchMeta,
// @ts-ignore
__previousQueryOptions,
},
});
break;
}
case "ACTION-RESTORE-ERROR": {
queryClient.resetQueries(activeQuery);
break;
}
case "ACTION-TRIGGER-LOADING": {
const __previousQueryOptions = activeQuery.options;
// Trigger a fetch that never resolves to simulate loading
activeQuery.fetch({
...__previousQueryOptions,
queryFn: () => new Promise(() => {}),
gcTime: -1,
});
activeQuery.setState({
data: undefined,
status: "pending",
fetchMeta: {
...activeQuery.state.fetchMeta,
// @ts-ignore
__previousQueryOptions,
},
});
break;
}
case "ACTION-RESTORE-LOADING": {
const previousState = activeQuery.state;
const previousOptions = activeQuery.state.fetchMeta
? (activeQuery.state.fetchMeta as any).__previousQueryOptions
: null;
activeQuery.cancel({ silent: true });
activeQuery.setState({
...previousState,
fetchStatus: "idle",
fetchMeta: null,
});
if (previousOptions) {
activeQuery.fetch(previousOptions);
}
break;
}
case "ACTION-RESET": {
queryClient.resetQueries(activeQuery);
break;
}
case "ACTION-REMOVE": {
queryClient.removeQueries(activeQuery);
break;
}
case "ACTION-REFETCH": {
activeQuery.fetch().catch(() => {});
break;
}
case "ACTION-INVALIDATE": {
queryClient.invalidateQueries(activeQuery);
break;
}
case "ACTION-ONLINE-MANAGER-ONLINE": {
onlineManager.setOnline(true);
break;
}
case "ACTION-ONLINE-MANAGER-OFFLINE": {
onlineManager.setOnline(false);
break;
}
}
}
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so should we make the devtools emit those events and you’d directly listen to those?
Yes!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, just to be on the same page: this would mean no changes to the query-core
, right? because those messages wouldn’t go through the query cache...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay great 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ardeora can you have a look here please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added events for query actions to make it easy to capture them in external dev tools on mobile devices.
These events allow my external web interface to work seamlessly across any mobile framework or device using TanStack Query.
Plugin https://github.com/LovesWorking/tanstack-query-dev-tools-expo-plugin/tree/main
Example https://github.com/LovesWorking/RN-Dev-Tools-Example/tree/master
Mac App
https://github.com/LovesWorking/rn-better-dev-tools
Preview
iphone.testing.mov