bgaleotti / react-query-native-devtools

161 stars 19 forks source link

Not working with TanStack v5 #113

Open ericledonge opened 9 months ago

ericledonge commented 9 months ago

I was trying to use it with TanStack v5 but it wasn't working.

I've downgraded to v4 and it's working.

Thank you for your work! This plugin is a must have for us!

sairus2k commented 9 months ago

I can confirm the react-query-native-devtools plugin does not work properly with tanstack/query v5. When trying to use it in my own project with the latest v5 release, I ran into the same error reported:

"TypeError: Cannot read properties of undefined (reading 'length') at getObserversCounter"

This occurred for me in Flipper after upgrading from tanstack/query v4 to v5. Downgrading back to v4 resolved the issue, so it seems there is an incompatibility introduced in v5 that is causing problems for the plugin.

I'm reporting this here to help add another confirmation of the problem. Hopefully more visibility on the incompatibility will help get it resolved sooner. I find this plugin invaluable for debugging and monitoring React Query in my React Native apps, so I'm eager to get it working again with the latest TanStack release.

Thanks for building this great tool.

YOEL311 commented 8 months ago

Check null before variable access to solve the bag issue.

@sairus2k @ericledonge you can check it in this Flipper plugin file

flipper-plugin-react-query-native-devtools-v4.1.4.tgz

you can install it in your Flipper

image

sairus2k commented 8 months ago

@YOEL311 It works for me, thanks!

joshsmith-watchbox commented 7 months ago

The above fix allowed the plugin to start functioning again, but now it's revealing that the query status + active states are all showing as inactive and false, respectively.

Think there might be a deeper issue here caused by the V5 changes @YOEL311

image
YOEL311 commented 7 months ago

hey @joshsmith-watchbox I checked that It happened because the react-query data changed I attached the data with react-query V4 and react-query V5

the react-query-native-devtools library get event from the react-query withqueryCache.subscribe to send it to flipper

https://github.com/bgaleotti/react-query-native-devtools/blob/799efff17b08e9793ab27d5a93457c5d5510233c/packages/react-query-native-devtools/src/index.ts#L40-L54

but the data of the event is changed this old data that get in an event in react-query-V4 you can see it contains an observes array with an option object Inside (that contains the enable field -inactive)

{
  "abortSignalConsumed": true,
  "cache": {
    "config": {},
    "listeners": [
      [Function anonymous
      ]
    ],
    "queries": [
      [Circular
      ]
    ],
    "queriesMap": {
      "[\"EXAMPLE_KEY\",{\"user\":3}]": [Circular
      ]
    },
    "subscribe": [Function bound subscribe
    ]
  },
  "cacheTime": 300000,
  "defaultOptions": undefined,
  "gcTimeout": 67,
  "initialState": {
    "data": undefined,
    "dataUpdateCount": 0,
    "dataUpdatedAt": 0,
    "error": null,
    "errorUpdateCount": 0,
    "errorUpdatedAt": 0,
    "fetchFailureCount": 0,
    "fetchMeta": null,
    "fetchStatus": "idle",
    "isInvalidated": false,
    "status": "loading"
  },
  "isFetchingOptimistic": false,
  "logger": {
    "error": [Function anonymous
    ],
    "log": [Function anonymous
    ],
    "warn": [Function anonymous
    ]
  },
  "meta": undefined,
  "observers": [                            // <- observers array
    {
      "client": [QueryClient
      ],
      "currentQuery": [Circular
      ],
      "currentQueryInitialState": [Object
      ],
      "currentRefetchInterval": false,
      "currentResult": [Object
      ],
      "currentResultOptions": [Object
      ],
      "currentResultState": [Object
      ],
      "listeners": [Array
      ],
      "options":                                 // <- options object
        {
          "_defaulted": true,
          "_optimisticResults": "optimistic",
          "enabled": true,                              // <- enabled
          "queryFn": [Function queryFn
          ],
          "queryHash": "[\"EXAMPLE_KEY\",{\"user\":3}]",
          "queryKey": [
            "EXAMPLE_KEY",
            {
              "user": 3
            }
          ],
          "refetchOnReconnect": true,
          "retry": 0,
          "staleTime": Infinity,
          "useErrorBoundary": false
        },
      "previousQueryResult": undefined,
      "refetch": [Function bound refetch
      ],
      "remove": [Function bound remove
      ],
      "selectError": null,
      "subscribe": [Function bound subscribe
      ],
      "trackedProps": [Set
      ]
    }
  ],
  "options": {
    "_defaulted": true,
    "_optimisticResults": "optimistic",
    "enabled": true,
    "queryFn": [Function queryFn
    ],
    "queryHash": "[\"EXAMPLE_KEY\",{\"user\":3}]",
    "queryKey": [
      "EXAMPLE_KEY",
      [Object
      ]
    ],
    "refetchOnReconnect": true,
    "retry": 0,
    "staleTime": Infinity,
    "useErrorBoundary": false
  },
  "promise": {
    "_h": 1,
    "_i": 1,
    "_j": {
      "title": "response.title"
    },
    "_k": null
  },
  "queryHash": "[\"EXAMPLE_KEY\",{\"user\":3}]",
  "queryKey": [
    "EXAMPLE_KEY",
    {
      "user": 3
    }
  ],
  "retryer": {
    "cancel": [Function cancel
    ],
    "cancelRetry": [Function cancelRetry
    ],
    "continue": [Function _continue
    ],
    "continueRetry": [Function continueRetry
    ],
    "promise": {
      "_h": 1,
      "_i": 1,
      "_j": [Object
      ],
      "_k": null
    }
  },
  "revertState": {
    "data": undefined,
    "dataUpdateCount": 0,
    "dataUpdatedAt": 0,
    "error": null,
    "errorUpdateCount": 0,
    "errorUpdatedAt": 0,
    "fetchFailureCount": 0,
    "fetchMeta": null,
    "fetchStatus": "idle",
    "isInvalidated": false,
    "status": "loading"
  },
  "state": {
    "data": {
      "title": "response.title"
    },
    "dataUpdateCount": 1,
    "dataUpdatedAt": 1701895085093,
    "error": null,
    "errorUpdateCount": 0,
    "errorUpdatedAt": 0,
    "fetchFailureCount": 0,
    "fetchMeta": null,
    "fetchStatus": "idle",
    "isInvalidated": false,
    "status": "success"
  }
}

but in react-query-V5 we do not get the observer array at all

// V 5
{
  "gcTime": 300000,
  "isFetchingOptimistic": false,
  "options": {
    "_defaulted": true,
    "_optimisticResults": "optimistic",
    "enabled": true,
    "queryFn": [Function queryFn
    ],
    "queryHash": "[\"EXAMPLE_KEY\",{\"user\":3}]",
    "queryKey": [
      "EXAMPLE_KEY",
      [Object
      ]
    ],
    "refetchOnReconnect": true,
    "retry": 0,
    "staleTime": Infinity,
    "throwOnError": false
  },
  "queryHash": "[\"EXAMPLE_KEY\",{\"user\":3}]",
  "queryKey": [
    "EXAMPLE_KEY",
    {
      "user": 3
    }
  ],
  "state": {
    "data": {
      "title": "response.title"
    },
    "dataUpdateCount": 1,
    "dataUpdatedAt": 1701894630567,
    "error": null,
    "errorUpdateCount": 0,
    "errorUpdatedAt": 0,
    "fetchFailureCount": 0,
    "fetchFailureReason": null,
    "fetchMeta": null,
    "fetchStatus": "idle",
    "isInvalidated": false,
    "status": "success"
  }
}

is very odd because in react-query code you can see the type of the notify function get event with this type QueryCacheNotifyEvent that contain observers

https://github.com/TanStack/query/blob/9b1aa77010637506b929f529a12bd6dfc6f9001a/packages/query-core/src/queryCache.ts#L192-L198

https://github.com/TanStack/query/blob/9b1aa77010637506b929f529a12bd6dfc6f9001a/packages/query-core/src/queryCache.ts#L71-L78

https://github.com/TanStack/query/blob/9b1aa77010637506b929f529a12bd6dfc6f9001a/packages/query-core/src/query.ts#L146-L166

 notify(event: QueryCacheNotifyEvent) {
    notifyManager.batch(() => {
      this.listeners.forEach((listener) => {
        listener(event)
      })
    })
  }

export type QueryCacheNotifyEvent =
  | NotifyEventQueryAdded
...

interface NotifyEventQueryAdded extends NotifyEvent {
  type: 'added'
  query: Query<any, any, any, any>
}

export class Query<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
> extends Removable {
  queryKey: TQueryKey
  queryHash: string
  options!: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
...
  #observers: Array<QueryObserver<any, any, any, any, any>>
YOEL311 commented 7 months ago

I think I have found the problem. this Query class in react-query V5

https://github.com/TanStack/query/blob/9b1aa77010637506b929f529a12bd6dfc6f9001a/packages/query-core/src/query.ts#L146-L166


export class Query<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
> extends Removable {
  queryKey: TQueryKey
  queryHash: string
  options!: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
  state: QueryState<TData, TError>
  isFetchingOptimistic?: boolean

  #initialState: QueryState<TData, TError>
  #revertState?: QueryState<TData, TError>
  #cache: QueryCache
  #promise?: Promise<TData>
  #retryer?: Retryer<TData>
  #observers: Array<QueryObserver<any, any, any, any, any>>
  #defaultOptions?: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
  #abortSignalConsumed: boolean

and this Query class in V4

https://github.com/TanStack/query/blob/377a7b19bda9a9e2fb842c8b6585bebd3b18d686/packages/query-core/src/query.ts#L141-L161


export class Query<
  TQueryFnData = unknown,
  TError = unknown,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
> extends Removable {
  queryKey: TQueryKey
  queryHash: string
  options!: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
  initialState: QueryState<TData, TError>
  revertState?: QueryState<TData, TError>
  state: QueryState<TData, TError>
  isFetchingOptimistic?: boolean

  private cache: QueryCache
  private logger: Logger
  private promise?: Promise<TData>
  private retryer?: Retryer<TData>
  private observers: QueryObserver<any, any, any, any, any>[]
  private defaultOptions?: QueryOptions<TQueryFnData, TError, TData, TQueryKey>
  private abortSignalConsumed: boolean

Maybe changing the data type of the 'observers' property can make a difference.

marianoagopian commented 6 months ago

Hi, I also have this problem. Please let me know when fixed.

anton-patrushev commented 2 months ago

Is there any plan to release at least v4.1.4 that just makes the flipper plugin work (to show queries and its data)?

Is there any plan to prepare a new version and release (let's say 5.0.0) that is fully compatible with query v5 and does not have that status field bug and other mentioned issues above?

Does anyone work on any of these 2 topics?

cc: @bgaleotti

joshsmith-watchbox commented 1 month ago

@anton-patrushev I took a look at the latest Tanstack docs, and it has been updated with a reference to a separate plugin that supports React Query v5: react-native-react-query-devtools.

It does appear there is a requirement of being on React Native 0.73.2 or above and React Query 5.17.19 or above. Still, might be worth a look as an alternative to this library until support for React Query v5 is added.

anton-patrushev commented 1 month ago

hey @joshsmith-watchbox

BTW, this is actually what I end up with for dubbing and inspecting tanstack query

But this not definitely not ideal and not what we want — I would rather have a flipper tool for that to have all my debugging things there instead of in-app view.

From the other side, my main concern is about flipper + react-native future — sounds like the react-native team is moving in a different direction — and that would certainly cause another way of thinking in the community. So we may not see a flipper as the popular debugging tool for react-native apps.