apollo-client: TypeError: undefined is not an object when calling refetch from useQuery hook

Intended outcome: I have a react-native flatlist and I am dragging to refresh the current feed. I expected the original query to be refetch from the server and new data would be populated.

Same problem with fetchMore, I scroll down the flatlist and I expect query to add data to the list and continue scrolling through the additions.

Actual outcome: I receive an error and the app crashes (both for refetch and fetchmore).

[Unhandled promise rejection: TypeError: undefined is not an object (evaluating '_this.currentObservable.refetch')]
- node_modules/@apollo/client/react/data/data.cjs.js:324:48 in _this.getQueryResult
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:293:29 in invoke
- node_modules/regenerator-runtime/runtime.js:63:36 in tryCatch
- node_modules/regenerator-runtime/runtime.js:154:27 in invoke
- node_modules/regenerator-runtime/runtime.js:189:16 in PromiseImpl$argument_0
- node_modules/promise/setimmediate/core.js:45:6 in tryCallTwo
- node_modules/promise/setimmediate/core.js:200:22 in doResolve
- node_modules/promise/setimmediate/core.js:66:11 in Promise
- node_modules/regenerator-runtime/runtime.js:188:15 in callInvokeWithMethodAndArg
- node_modules/regenerator-runtime/runtime.js:211:38 in enqueue
- node_modules/regenerator-runtime/runtime.js:238:8 in exports.async
- node_modules/react-native/Libraries/Components/RefreshControl/RefreshControl.js:196:28 in _onRefresh
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:286:4 in invokeGuardedCallbackImpl
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:497:2 in invokeGuardedCallback
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:521:2 in invokeGuardedCallbackAndCatchFirstError
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:683:41 in executeDispatch
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:707:19 in executeDispatchesInOrder
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:872:28 in executeDispatchesAndRelease
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:853:4 in forEachAccumulated
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:897:20 in runEventsInBatch
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:1069:18 in runExtractedPluginEventsInBatch
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:2835:35 in batchedUpdates$argument_0
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:20569:13 in batchedUpdates$1
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:2731:29 in batchedUpdates
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:2834:16 in _receiveRootNodeIDEvent
- node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js:2854:25 in receiveEvent
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:425:19 in __callFunction
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:112:6 in __guard$argument_0
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:373:10 in __guard
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:111:4 in callFunctionReturnFlushedQueue
* [native code]:null in callFunctionReturnFlushedQueue

How to reproduce the issue: Flatlist code:

export default function DiscoverFeed({ navigation }) {
  const theme = useTheme();

  const { data, error, loading, refetch, fetchMore } = useQuery(
    GET_RECIPE_FEED,
    {
      variables: { offset: 0 },
    }
  );

  if (error) return <Text>There was an error, try and reload.</Text>;
  if (loading) return <Loader />;

  const renderItem = ({ item }) => {
    return (
      <View style={styles.cardItems}>
        <RecipeCard item={item} navigation={navigation} />
      </View>
    );
  };

  return (
    <SafeAreaView style={styles.safeContainer} edges={["right", "left"]}>
      <FlatList
        style={styles.flatContainer}
        data={data.recipe}
        removeClippedSubviews={true}
        renderItem={renderItem}
        refreshing={loading}
        onRefresh={() => {
          refetch();
        }}
        keyExtractor={(item) => item.id.toString()}
        onEndReachedThreshold={0.5}
        onEndReached={() => {
          // The fetchMore method is used to load new data and add it
          // to the original query we used to populate the list
          fetchMore({
            variables: {
              offset: data.recipe.length,
            },
          });
        }}
      />
    </SafeAreaView>
  );
}

typePolicy:

// Type policy to manage pagination and receiving new data
export const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        recipe: {
          merge: (existing = [], incoming, { args }) => {
            // On initial load or when adding a recipe, offset is 0 and only take the incoming data to avoid duplication
            if (args.offset == 0) {
              return [...incoming];
            }
            // This is only for pagination
            return [...existing, ...incoming];
          },
        },
      },
    },
  },
});

Query:

export const GET_RECIPE_FEED = gql`
  query GetRecipeFeed($offset: Int) {
    recipe(order_by: { updated_at: desc }, limit: 5, offset: $offset)
      @connection(key: "recipe") {
      id
      title
      description
      images_json
      updated_at
      dishtype
      difficulty
      duration
      recipe_tags {
        tag {
          tag
        }
      }
    }
  }
`;

Versions System: OS: macOS 10.15.6 Binaries: Node: 14.6.0 - /usr/local/bin/node npm: 6.14.7 - /usr/local/bin/npm Browsers: Firefox: 79.0 Safari: 13.1.2 npmPackages: @apollo/client: ^3.1.3 => 3.1.3 @apollo/link-context: ^2.0.0-beta.3 => 2.0.0-beta.3 apollo-cache-persist: ^0.1.1 => 0.1.1

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 25
  • Comments: 47 (2 by maintainers)

Most upvoted comments

I’m using @apollo/client v3.2.0 + Expo v39 and I’m able to use useLazyQuery as a workaround!

const [fetchData, { data, refetch, loading }] = useLazyQuery(GQL_QUERY, { variables });

React.useEffect(() => {
  fetchData();
}, []);

...

return (
  <FlatList
    ...
    onRefresh={refetch} // this works now!
  />
);

This is also happening to me when calling fetchMore in a scroll event. I’m on the ^3.3.16 version.

Just installed version 3.2.0 and still having this problem on react-native.

@psamim, did you try disabling fast refresh and see if you still get the error?

I’m using @apollo/client v3.2.0 + Expo v39 and I’m able to use useLazyQuery as a workaround!

const [fetchData, { data, refetch, loading }] = useLazyQuery(GQL_QUERY, { variables });

React.useEffect(() => {
  fetchData();
}, []);

...

return (
  <FlatList
    ...
    onRefresh={refetch} // this works now!
  />
);

@aakagi’s solution worked well for me on @apollo/client v3.1.4, swapped out all useQuery with useLazyQuery and did the initial fetch in a useEffect, just as shown above. No more fast reload errors. Thanks for all the help!

I just ran into this upgrading from apollo-client/v2 to @apollo/client@3.1.4 and found this happening in any existing components that use refetch, downgrading back to 3.0.2 as @cc-dev-leader suggested seems to be an okay work-around so far.

Hi, recently noticed that we’ve the same error.

Using 3.0.2 again solved our problem.

@apollo/client: ^3.1.3 => ^3.0.2 Actual updates next: ^9.5.2 next-apollo: ^5.0.0

After trying several suggestions including useLazyQuery with no success, I upgraded @apollo/clientto 3.3.12 and that fixed it for me

simulator_screenshot_5C873C71-28F5-4954-B8CB-9C0B75E2EC80

@apollo/client”: “^3.3.16”,

I found a fix for my issue:

import React from "react";
import { InteractionManager } from "react-native";

export const useIsPageTransitioning = (): boolean => {
  const [isTransitioning, setIsTransitioning] = React.useState(true);
  React.useEffect(() => {
    const h = InteractionManager.runAfterInteractions(() => {
      setIsTransitioning(false);
    });
  }, []);

  return isTransitioning;
};

change to:

import React from "react";
import { InteractionManager } from "react-native";

export const useIsPageTransitioning = (): boolean => {
  const [isTransitioning, setIsTransitioning] = React.useState(true);
  React.useEffect(() => {
    const h = InteractionManager.runAfterInteractions(() => {
      setIsTransitioning(false);
    });
    return () => h.cancel();
  }, []);

  return isTransitioning;
};

Upgrade to 3.2.7 solved the problem in my case

Upgrading from 3.2.5 to 3.3.0-rc.0 fixed this issue for me.

This appears to be a continuation of the issue here: https://github.com/apollographql/react-apollo/issues/3600

@Svarto Thanks. Yes ti solved the problem.

@Poky85 This matches my use case too, only get it with fast refresh and not in production!