React-apollo: TypeError - undefined is not an object (evaluating 'c.currentObservable.query.refetch')

Created on 6 Apr 2020  路  5Comments  路  Source: apollographql/react-apollo

Intended outcome:

The user does not experience an exception being thrown when navigating around the current page.

Actual outcome:

We have received several non fatal crash reports around the same screen
TypeError - undefined is not an object (evaluating 'c.currentObservable.query.refetch') which is occurring at react-hooks.cjs.js:119:43 when checking the stack traces of these reports it seems like we have narrowed down the error to a possible location to two functions.

const debouncedSearch = useMemo(() => debounce((text) => {
    analytics.track('Search', {
      text,
      screen: navigation.state.routeName,
    });
    refetch({
      input: {
        keywordSearch: text,
        ...filterQuery.input,
      }
    });
  }, 800), [refetch, filterQuery]);

  const debouncedFilter = useMemo(() => debounce((index) => {
    refetch({
      input: {
        ...filterQuery.input,
        pagingData: {
          ...filterQuery.input.pagingData,
          sort: [
            queryOptions
          ]
        }
      }
    });
  }, 800), [refetch, filterQuery]);

where filterQuery and queryOptions are evaluated prior to this, and refetch is from the query hook

 const { data, fetchMore, isRefetching, loading, hasError, refetch, variables } = useQuery(
    query,
    {
      variables: filterQuery,
      notifyOnNetworkStatusChange: true,
      fetchPolicy: 'network-only',
    }
  );

both the debouncedSearch and debouncedFilter are then used in a header we position above a react nativeSectionList. Within that section list when the user scrolls to the bottom we fetch more with the query if there is more data in the paginated query.

How to reproduce the issue:

I have not been able to recreate this problem in a local environment. I have attempted to seed a very large list, render that in our SectionList and fetch more data many times while triggering both debouncedSearch and debouncedFilter but no exception gets thrown.

Version

  System:
    OS: macOS High Sierra 10.13.6
  Binaries:
    Node: 12.4.0 - ~/.nvm/versions/node/v12.4.0/bin/node
    Yarn: 1.17.3 - /usr/local/bin/yarn
    npm: 6.9.0 - ~/.nvm/versions/node/v12.4.0/bin/npm
  Browsers:
    Chrome: 80.0.3987.122
    Firefox: 68.4.1
    Safari: 13.0.3
  npmPackages:
    apollo-cache-inmemory: ^1.5.1 => 1.6.3 
    apollo-client: 2.6.x => 2.6.4 
    apollo-link: ^1.2.11 => 1.2.12 
    apollo-link-batch-http: ^1.2.13 => 1.2.13 
    apollo-link-context: ^1.0.17 => 1.0.18 
    apollo-link-error: ^1.1.10 => 1.1.11 
    apollo-link-timeout: ^1.3.1 => 1.3.1 
    apollo-test-utils: ^0.3.2 => 0.3.2 
    react-apollo: ~3.1.3 => 3.1.3 

Let me know if more information is needed and I will try to add detail the best that I can.

Most helpful comment

This also occurs in React Native when you have a useFocusedEffect that triggers when a user refocuses/returns to a screen

All 5 comments

This also occurs in React Native when you have a useFocusedEffect that triggers when a user refocuses/returns to a screen

Getting this error when using it like this

React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      refetch();
    });
    return unsubscribe;
  }, [navigation]);

I notice that this is happening when the hot reload triggers

const Profile = () => {
  const { loading, data, refetch, networkStatus } = useQuery(
    userProfile
  );
  if (loading) return <Text>Loading...</Text>;
  if (data) {
    return (
      <Container>
        <ScrollView
          refreshControl={
            <RefreshControl
              refreshing={networkStatus === NetworkStatus.refetch}
              onRefresh={refetch}
            />
          }>
          <ProfileView profile={data.profile} />
        </ScrollView>
      </Container>
    );
  }
};

I see this issue as well.
I'm using "on scroll down refresh" and I'm getting this message.
Any potential workaround?

Can you try the following:

const _refetch = useCallback(() => {
    const task = InteractionManager.runAfterInteractions(async () => {
      if (refetch) await refetch()
    })
    return () => task.cancel()
  }, [refetch])
Was this page helpful?
0 / 5 - 0 ratings