Skip to content

Commit 696fd44

Browse files
LovesWorkingTkDodoautofix-ci[bot]
authored
feat(devtools): 🏝️ TanStack Query DevTools for Expo/React Native! πŸš€ (#8846)
* test * feat(devtools): add action event types and notify functionality for query actions * cleanup commeny * fix(devtools): update notifyDevtools to use queryClient for all action notifications * remove dup call * Fix online manager bug not syncing correctly * Update docs * Fix default case error due to additional events from dev tools. * Add events * ci: apply automated fixes * Remove no longer needed code * ci: apply automated fixes * revert previous change * undo minor text change * ci: apply automated fixes * Update packages/query-devtools/src/Devtools.tsx * Apply suggestions from code review --------- Co-authored-by: Dominik Dorfmeister <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 6a52926 commit 696fd44

File tree

3 files changed

+102
-24
lines changed

3 files changed

+102
-24
lines changed

β€Ždocs/framework/react/devtools.md

+1-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ Wave your hands in the air and shout hooray because React Query comes with dedic
77

88
When you begin your React Query journey, you'll want these devtools by your side. They help visualize all the inner workings of React Query and will likely save you hours of debugging if you find yourself in a pinch!
99

10-
> Please note that for now, the devtools **do not support React Native**. If you would like to help us make the devtools platform-agnostic, please let us know!
11-
12-
> Exciting News: We now have a separate package for React Native React Query DevTools! This new addition brings native support, allowing you to integrate DevTools directly into your React Native projects. Check it out and contribute here: [react-native-react-query-devtools](https://github.com/LovesWorking/react-native-react-query-devtools)
13-
14-
> An external tool is also available that enables the use of React Query DevTools via an external dashboard. Find out more and contribute on [react-query-external-sync](https://github.com/LovesWorking/react-query-external-sync)
10+
> For React Native users: A third-party native macOS app is available for debugging React Query in ANY js-based application. Monitor queries across devices in real-time. Check it out here: [rn-better-dev-tools](https://github.com/LovesWorking/rn-better-dev-tools)
1511
1612
> Note that since version 5, the dev tools support observing mutations as well.
1713

β€Ždocs/framework/react/react-native.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ id: react-native
33
title: React Native
44
---
55

6-
React Query is designed to work out of the box with React Native, with the exception of the devtools, which are only supported with React DOM at this time.
6+
React Query is designed to work out of the box with React Native.
77

8-
There is a 3rd party [Expo](https://docs.expo.dev/) plugin which you can try: https://github.com/expo/dev-plugins/tree/main/packages/react-query
8+
## DevTools Support
99

10-
There is a 3rd party [Flipper](https://fbflipper.com/docs/getting-started/react-native/) plugin which you can try: https://github.com/bgaleotti/react-query-native-devtools
10+
There are several options available for React Native DevTools integration:
1111

12-
There is a 3rd party [Reactotron](https://github.com/infinitered/reactotron/) plugin which you can try: https://github.com/hsndmr/reactotron-react-query
12+
1. **Native macOS App**: A 3rd party app for debugging React Query in any js-based application:
13+
https://github.com/LovesWorking/rn-better-dev-tools
1314

14-
If you would like to help us make the built-in devtools platform agnostic, please let us know!
15+
2. **Flipper Plugin**: A 3rd party plugin for Flipper users:
16+
https://github.com/bgaleotti/react-query-native-devtools
17+
18+
3. **Reactotron Plugin**: A 3rd party plugin for Reactotron users:
19+
https://github.com/hsndmr/reactotron-react-query
1520

1621
## Online status management
1722

β€Žpackages/query-devtools/src/Devtools.tsx

+91-14
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ export const Devtools: Component<DevtoolsPanelProps> = (props) => {
120120
const styles = createMemo(() => {
121121
return theme() === 'dark' ? darkStyles(css) : lightStyles(css)
122122
})
123+
const onlineManager = createMemo(
124+
() => useQueryDevtoolsContext().onlineManager,
125+
)
126+
onMount(() => {
127+
const unsubscribe = onlineManager().subscribe((online) => {
128+
setOffline(!online)
129+
})
130+
131+
onCleanup(() => {
132+
unsubscribe()
133+
})
134+
})
123135

124136
const pip = usePiPWindow()
125137

@@ -922,8 +934,10 @@ export const ContentView: Component<ContentViewProps> = (props) => {
922934
<button
923935
onClick={() => {
924936
if (selectedView() === 'queries') {
937+
sendDevToolsEvent({ type: 'CLEAR_QUERY_CACHE' })
925938
query_cache().clear()
926939
} else {
940+
sendDevToolsEvent({ type: 'CLEAR_MUTATION_CACHE' })
927941
mutation_cache().clear()
928942
}
929943
}}
@@ -939,13 +953,7 @@ export const ContentView: Component<ContentViewProps> = (props) => {
939953
</button>
940954
<button
941955
onClick={() => {
942-
if (offline()) {
943-
onlineManager().setOnline(true)
944-
setOffline(false)
945-
} else {
946-
onlineManager().setOnline(false)
947-
setOffline(true)
948-
}
956+
onlineManager().setOnline(!onlineManager().isOnline())
949957
}}
950958
class={cx(
951959
styles().actionsBtn,
@@ -1768,29 +1776,43 @@ const QueryDetails = () => {
17681776
const color = createMemo(() => getQueryStatusColorByLabel(statusLabel()))
17691777

17701778
const handleRefetch = () => {
1779+
sendDevToolsEvent({ type: 'REFETCH', queryHash: activeQuery()?.queryHash })
17711780
const promise = activeQuery()?.fetch()
17721781
promise?.catch(() => {})
17731782
}
17741783

17751784
const triggerError = (errorType?: DevtoolsErrorType) => {
1785+
const activeQueryVal = activeQuery()
1786+
if (!activeQueryVal) return
1787+
sendDevToolsEvent({
1788+
type: 'TRIGGER_ERROR',
1789+
queryHash: activeQueryVal.queryHash,
1790+
metadata: { error: errorType?.name },
1791+
})
17761792
const error =
1777-
errorType?.initializer(activeQuery()!) ??
1793+
errorType?.initializer(activeQueryVal) ??
17781794
new Error('Unknown error from devtools')
17791795

1780-
const __previousQueryOptions = activeQuery()!.options
1796+
const __previousQueryOptions = activeQueryVal.options
17811797

1782-
activeQuery()!.setState({
1798+
activeQueryVal.setState({
17831799
status: 'error',
17841800
error,
17851801
fetchMeta: {
1786-
...activeQuery()!.state.fetchMeta,
1802+
...activeQueryVal.state.fetchMeta,
17871803
__previousQueryOptions,
17881804
} as any,
17891805
} as QueryState<unknown, Error>)
17901806
}
17911807

17921808
const restoreQueryAfterLoadingOrError = () => {
1793-
const activeQueryVal = activeQuery()!
1809+
const activeQueryVal = activeQuery()
1810+
if (!activeQueryVal) return
1811+
1812+
sendDevToolsEvent({
1813+
type: 'RESTORE_LOADING',
1814+
queryHash: activeQueryVal.queryHash,
1815+
})
17941816
const previousState = activeQueryVal.state
17951817
const previousOptions = activeQueryVal.state.fetchMeta
17961818
? (activeQueryVal.state.fetchMeta as any).__previousQueryOptions
@@ -1899,7 +1921,13 @@ const QueryDetails = () => {
18991921
'tsqd-query-details-actions-btn',
19001922
'tsqd-query-details-action-invalidate',
19011923
)}
1902-
onClick={() => queryClient.invalidateQueries(activeQuery())}
1924+
onClick={() => {
1925+
sendDevToolsEvent({
1926+
type: 'INVALIDATE',
1927+
queryHash: activeQuery()?.queryHash,
1928+
})
1929+
queryClient.invalidateQueries(activeQuery())
1930+
}}
19031931
disabled={queryStatus() === 'pending'}
19041932
>
19051933
<span
@@ -1917,7 +1945,13 @@ const QueryDetails = () => {
19171945
'tsqd-query-details-actions-btn',
19181946
'tsqd-query-details-action-reset',
19191947
)}
1920-
onClick={() => queryClient.resetQueries(activeQuery())}
1948+
onClick={() => {
1949+
sendDevToolsEvent({
1950+
type: 'RESET',
1951+
queryHash: activeQuery()?.queryHash,
1952+
})
1953+
queryClient.resetQueries(activeQuery())
1954+
}}
19211955
disabled={queryStatus() === 'pending'}
19221956
>
19231957
<span
@@ -1936,6 +1970,10 @@ const QueryDetails = () => {
19361970
'tsqd-query-details-action-remove',
19371971
)}
19381972
onClick={() => {
1973+
sendDevToolsEvent({
1974+
type: 'REMOVE',
1975+
queryHash: activeQuery()?.queryHash,
1976+
})
19391977
queryClient.removeQueries(activeQuery())
19401978
setSelectedQueryHash(null)
19411979
}}
@@ -1964,6 +2002,10 @@ const QueryDetails = () => {
19642002
} else {
19652003
const activeQueryVal = activeQuery()
19662004
if (!activeQueryVal) return
2005+
sendDevToolsEvent({
2006+
type: 'TRIGGER_LOADING',
2007+
queryHash: activeQueryVal.queryHash,
2008+
})
19672009
const __previousQueryOptions = activeQueryVal.options
19682010
// Trigger a fetch in order to trigger suspense as well.
19692011
activeQueryVal.fetch({
@@ -2006,6 +2048,10 @@ const QueryDetails = () => {
20062048
if (!activeQuery()!.state.error) {
20072049
triggerError()
20082050
} else {
2051+
sendDevToolsEvent({
2052+
type: 'RESTORE_ERROR',
2053+
queryHash: activeQuery()?.queryHash,
2054+
})
20092055
queryClient.resetQueries(activeQuery())
20102056
}
20112057
}}
@@ -2438,6 +2484,37 @@ const createSubscribeToMutationCacheBatcher = <T,>(
24382484
return value
24392485
}
24402486

2487+
type DevToolsActionType =
2488+
| 'REFETCH'
2489+
| 'INVALIDATE'
2490+
| 'RESET'
2491+
| 'REMOVE'
2492+
| 'TRIGGER_ERROR'
2493+
| 'RESTORE_ERROR'
2494+
| 'TRIGGER_LOADING'
2495+
| 'RESTORE_LOADING'
2496+
| 'CLEAR_MUTATION_CACHE'
2497+
| 'CLEAR_QUERY_CACHE'
2498+
2499+
const DEV_TOOLS_EVENT = '@tanstack/query-devtools-event'
2500+
2501+
const sendDevToolsEvent = ({
2502+
type,
2503+
queryHash,
2504+
metadata,
2505+
}: {
2506+
type: DevToolsActionType
2507+
queryHash?: string
2508+
metadata?: Record<string, unknown>
2509+
}) => {
2510+
const event = new CustomEvent(DEV_TOOLS_EVENT, {
2511+
detail: { type, queryHash, metadata },
2512+
bubbles: true,
2513+
cancelable: true,
2514+
})
2515+
window.dispatchEvent(event)
2516+
}
2517+
24412518
const stylesFactory = (
24422519
theme: 'light' | 'dark',
24432520
css: (typeof goober)['css'],

0 commit comments

Comments
Β (0)