Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

loading stuck on true when using useQuery hook? #3270

Closed
MaxwellGover opened this issue Jul 22, 2019 · 54 comments · Fixed by #3313
Closed

loading stuck on true when using useQuery hook? #3270

MaxwellGover opened this issue Jul 22, 2019 · 54 comments · Fixed by #3313
Assignees
Milestone

Comments

@MaxwellGover
Copy link

MaxwellGover commented Jul 22, 2019

I forked the hooks example from the react-apollo repo and it seems like the value for loading is never being updated, even when the data is being returned properly?

Screen Shot 2019-07-22 at 4 43 39 PM

I set up my own project and was experiencing the same issue when using useQuery

UPDATE: After adding an item, useQuery seems to work fine

Screen Shot 2019-07-22 at 4 52 19 PM

Intended outcome:

value of loading changes to false when data is available

Actual outcome:

value of loading never updates to false

Version

{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@apollo/react-hooks": "beta",
    "@types/jest": "24.0.13",
    "@types/node": "12.6.8",
    "@types/react": "16.8.23",
    "@types/react-dom": "16.8.4",
    "apollo-cache-inmemory": "^1.6.0",
    "apollo-client": "^2.6.3",
    "apollo-link-http": "^1.5.14",
    "apollo-link-ws": "^1.0.17",
    "graphql": "^14.3.1",
    "graphql-tag": "^2.10.1",
    "react": "16.8.6",
    "react-dom": "16.8.6",
    "react-scripts": "3.0.1",
    "reactstrap": "^8.0.0",
    "subscriptions-transport-ws": "^0.9.16",
    "typescript": "3.5.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@types/graphql": "14.2.2",
    "@types/reactstrap": "8.0.1"
  }
}
@gilesbradshaw
Copy link
Contributor

I've been finding that sometimes I don't seem to get the second call of the component even though the data has loaded - I am currently triggering a state change with the onCompleted call back

  const [qRefresh, setQRefresh] = useState(0)

  const {
    data: d,
    loading,
    error,
    client: {
      store
    }
  } = useQuery<parameter, parameterVariables>(
    query,
    {
      onCompleted: (...params) => {
        setQRefresh(qRefresh + 1)
      },
      fetchPolicy: 'network-only',
      variables: {
        id,
      },
    },
  )

@Grmiade
Copy link

Grmiade commented Jul 23, 2019

@MaxwellGover FYI the previous version (@apollo/react-hooks 0.1.0-beta.10) seems to work for me.
I'm not longer stuck by the loading state.
You should try this version on your project I think, maybe it could be a good clue to debug this issue ;)

@gilesbradshaw
Copy link
Contributor

@MaxwellGover i just tried beta 10 and fixes my issue..

@gilesbradshaw
Copy link
Contributor

Also my components continually refresh when using beta 11 whereas when I change to beta 10 this stops happening - I suspect this is also related to the browser eventually crashing. beta 11 is unwell IMO

@hmeerlo
Copy link

hmeerlo commented Jul 24, 2019

I'm using react-apollo 3.0.0-beta4 which uses 0.1.0-beta.11 and I have the same issue. The loading state stays true and I can see in the network inspector that the data has arrived, it just has never re-rendered. I suspect it has something to do with the fact that I'm using 2 hook queries in 1 component?

@MichaelHindley
Copy link

@hmeerlo I don't think so, I am also using beta.11 and I have this issue with a simple 1 query component:

const BOOKS_GQL = gql`
    query GetBooks {
        books {
            id,
            author,
            title
        }
    }
`
const BookList = () => {
  const { loading, data } = useQuery<GetBooks>(BOOKS_GQL)
  if (loading) return <p>Loading...</p>
  if (!data) return <></>

  return (
    <div>
      {data.books.map((book, idx) => {
        return <p key={idx}>{book.title} by {book.author}</p>
      })}
    </div>
  )
}

const App = () => (
  <ApolloProvider client={client}>
    <div>
      <h2>Typehint all the things and eat delicious chicken wings</h2>
      <BookList />
    </div>
  </ApolloProvider>
)

@viniciusdacal
Copy link

I'm using 3.0.0-beta.4 as well, and I'm facing the same issue.

@viniciusdacal
Copy link

@hwillson any clue about this issue? If you give a direction, I could try to open a PR. I tried to investigate, but I couldn't grok QueryData entirely.

@MichaelHindley
Copy link

After some debugging locally, at least for me it only occurs when the result of the Query has 1 item. If the result of the Query has more than 1 item, loading does not get stuck in a false state.

@hmeerlo
Copy link

hmeerlo commented Jul 25, 2019

@MichaelHindley not for me, the result of the query is the same all the time, but it randomly exits the loading state. Maybe it's timing related or just random :-)

@Bedotech
Copy link

Bedotech commented Jul 26, 2019

I notice something really weird, if I set in the network panel some network throttling, for example, Fast 3G, everything work as excepted.

This implementation is not affected: https://github.com/trojanowski/react-apollo-hooks

@emilsjolander
Copy link

@Bedotech I think you are on to something. I just encountered this bug in our product after implementing caching on the server which means queries are returned a lot faster. If i introduce a slowing using a sleep on the server everything works as expected. Seems like some sort of race condition to me.

@viniciusdacal
Copy link

viniciusdacal commented Jul 26, 2019

There's definitely the race condition.
If I got it right, we are storing the whole state inside a ref object (useRef),
Changes to this object, doesn't trigger an update inside the component.
Which means, it could happen that loading is set to false, but the component doesn't react (re-render) to that change.

What happens sometimes, is that something else change in the component or in the tree, triggering a re-render and removing it from the stuck state.

Ideally, we should store data, loading, error, variables and so on using useState or useReducer

@pdemarino
Copy link

This seems to be manifesting itself in #3009 - the client-only data resolves immediately, triggering the race condition.

@hwillson
Copy link
Member

Hi all - I'm just getting back from vacation, and am slowly re-learning how to type. I'll digest this more thoroughly shortly.

@viniciusdacal
Copy link

Thank you @hwillson
If there's anything I can do to help, let me know.

@therahl
Copy link

therahl commented Jul 30, 2019

This is an issue for me as well. Currently getting around it by forcing multiple rerenders via state change from the onCompleted prop - it's ugly but working as a hack for now.

@thomas81528262
Copy link

onCompleted seems like a solution now...... any update?

@ehortle
Copy link

ehortle commented Aug 5, 2019

I was also experiencing this issue on "react-apollo": "^3.0.0-beta.4" but switching to "@apollo/react-hooks": "0.1.0-beta.10" as per @gilesbradshaw 's comment fixed my issue. Thanks, @gilesbradshaw !

@thomas81528262
Copy link

Should we roll back to 0.1.0-beta.10?

@hwillson
Copy link
Member

hwillson commented Aug 5, 2019

Does anyone here have a small runnable repro that shows this happening? This is on my radar to fix today, and a runnable repro would greatly help.

@hwillson
Copy link
Member

hwillson commented Aug 5, 2019

@MaxwellGover I can't seem to re-create this issue using a fork of the hooks example app. If it's still happening for you consistently, could you share your fork so I could try it out directly?

@Bedotech The internals of react-apollo-hooks are quite a bit different than this project, so I'm not surprised to hear it's working with react-apollo-hooks. There's a bug here somewhere for sure.

@viniciusdacal our use of useRef should be okay here. We're leveraging useRef to abstract a lot of the internals out of the hook itself (for future reasons), but lifecycle updates should still be reflected properly back in the wrapping component. If useRef was to blame here we would see quite a few other failures in our test suite. But, bugs will be bugs, so I'll definitely keep your suggestion in mind while debugging.

@hwillson
Copy link
Member

hwillson commented Aug 5, 2019

Hmm - #3299 definitely sounds related. I'll run with that repro for now.

@jBugman
Copy link

jBugman commented Aug 5, 2019

This also reproduces for me on beta11 (but not 10) with @client query (and custom resolver for this query if this helps).

@hwillson
Copy link
Member

hwillson commented Aug 5, 2019

I've found the issue; it's a race condition between the response coming back through the internal Apollo Client ObservableQuery subscription and the component being marked as mounted. When a response comes back from AC via the Observable, we manually trigger a component update. That update is blocked if the component is marked as not being mounted. The component is marked as being mounted via a useEffect call, but sometimes data comes back via the Observable before the useEffect has a chance to fire. I'm just nailing down some tests for this, but a PR is coming shortly. Thanks all!

hwillson added a commit that referenced this issue Aug 5, 2019
When new data or errors are reported back through the
`ObservableQuery` subscription, `updateCurrentData` is called to
trigger a forced update of the parent component (to reflect the
new component state). Before triggering the forced update however,
`updateCurrentData` first checks to see if the component is
mounted (since we don't want to try to trigger a forced update on
a copmonent that isn't mounted). Unfortunately, a component
isn't marked as being mounted until the `afterExecute` method is
called via a `useEffect`. Under certain circumstances it's
possible for the `ObservableQuery` subscription to be
initialized and get data back before the `useEffect` has fired
and marked the component as mounted. This means when
`updateCurrentData` is triggered with valid updates, they're
sometimes blocked, and the component gets stuck in a permanent
loading state.

Due to other recent cleanup changes, we're now tracking the
destruction of the `ObservableQuery` subscription in a
`useEffect` within `useBaseQuery`. The subscription cleanup
is fired only when the component unmounts, and since we're
only calling `updateCurrentData` from within the subscription
callback, we don't need to have an extra `isMounted` check
before forcing an update. To this end, these changes get rid of
`updateCurrentData` completely. The `ObservableQuery`
subscription now always calls `forceUpdate` directly, and as
long as the component is mounted (tracked by React), it will
always force an update. This prevents race conditions between
data attempting to be updated, and the component not yet being
marked as mounted.

Fixes #3270.
Fixes #3299.
@jBugman
Copy link

jBugman commented Aug 5, 2019

Update to .12 fixed my issue too

@thomas81528262
Copy link

update to .12 fixed issue!!!!!!!!!!

@simmo
Copy link

simmo commented Aug 6, 2019

.12 is also fixing it for me.

@nicoglennon
Copy link

Thanks for the quick fix and the awesome library @hwillson!

@cthurston
Copy link

I'm still getting this on react-apollo@3.0.1, @apollo/react-hooks@3.0.1.

You can inspect the network and see that the request has completed with data, but it still will say loading.

It works sometimes. When I first began this morning is successfully set loading=false, but on the second load it didn't (even on hard refresh). Then every 30 minutes or so it will set loading=false. Maybe related to development/hot-reloading.

@temm1210
Copy link

temm1210 commented Aug 21, 2019

well i faced this issue on @apollo/react-hooks:0.1.0-beta.10. but in my case it is no longer visible on @apollo/react-hooks@3.0.1 until now

@ehortle
Copy link

ehortle commented Sep 2, 2019

Contrary to my above comment, I am still getting this issue. However, only in our live deployment, not in local dev... No idea where to look though. Would be happy to try to generate a reproduction but not sure where to start if it's only in live! Open to ideas if anybody has any...

@petetnt
Copy link
Contributor

petetnt commented Sep 5, 2019

Having the same issue with both @3.0.1 and the @3.1.0-beta.0 in development. The query resolves correctly, but the data doesn't get filled and loading is stuck to true.

Related deps:

    "@apollo/react-hooks": "3.1.0-beta.0",
    "apollo-cache": "^1.3.2",
    "apollo-cache-inmemory": "^1.2.1",
    "apollo-client": "^2.6.4",
    "apollo-link-context": "^1.0.5",
    "apollo-link-error": "^1.0.5",
    "apollo-link-http": "^1.3.3",
    "apollo-link-rest": "^0.3.1",
    "apollo-link-schema": "^1.1.0",
    "apollo-server-express": "^2.1.0",
    "apollo-upload-client": "^9.1.0",
    "apollo-utilities": "^1.3.2",
    "react-apollo": "3.1.0-beta.0",
    "graphql": "14.3.1",
    "graphql-anywhere": "^4.1.22",
    "graphql-cli": "2.15.14",
    "graphql-tag": "^2.8.0",
    "graphql-tools": "4.0.5"

Query is just a simple query:

const GET_DATA = gql`
  query GetData(
    $ID: String!,
  ) {
    GetDataFoo(
      ID: $ID,
    ) {
      data {
        time
        foo
      }
    }
  }
`;

...
  const x = useQuery(GET_DATA, {
    variables: {
      id
    },
  });

@diazdell91
Copy link

diazdell91 commented Sep 6, 2019

some new solution? @hwillson

@armanrozika
Copy link

armanrozika commented Sep 13, 2019

Face same issue here:
"@apollo/react-hooks": "^3.1.0",
"apollo-cache-inmemory": "^1.6.3",
"apollo-client": "^2.6.4",
"apollo-link-http": "^1.5.16"

Been searching online for hours for this now, and I just did a hacky way to solve it, by using errorPolicy: "ignore". It can't read the graphql error (or it can?), but it returns data.yourData as false, so I use that instead to show error on the UI, ended up hardcode the error message from frontend tho.

@Colafornia
Copy link

Contrary to my above comment, I am still getting this issue. However, only in our live deployment, not in local dev... No idea where to look though. Would be happy to try to generate a reproduction but not sure where to start if it's only in live! Open to ideas if anybody has any...

Same problem, although I have upgraded to:
"@apollo/react-hooks": "^3.1.2",

@AlvinRapada
Copy link

still a problem with "@apollo/react-hooks": "^3.1.2"

@Adzz
Copy link

Adzz commented Nov 10, 2019

I m getting the same problem locally. I can see the query has returned results in the chrome network tab:

Screenshot 2019-11-10 at 19 17 08

More over if I do this:

const link = new HttpLink({ uri: "https://localhost:4001/api" });
const cache = new InMemoryCache();
const client = new ApolloClient({ cache, link });
client
  .query({
    query: gql`
      {
        property {
          images {
            url
          }
        }
      }
    `,
  })
  .then((result) => console.log(result));

It also console logs what I would expect. However in the component, when using a hook:

  const { loading, error, data } = useQuery(IMAGE_QUERY, {
    notifyOnNetworkStatusChange: true,
  });
  
  console.log(data);
  console.log(error);
  console.log(loading);

Data is always undefined as is the error object, network status of 1. I would copy you the whole result of the useQuery but that seems impossible (can't stringify it as it's circular...)

@br-dev
Copy link

br-dev commented Nov 14, 2019

I seem to have this same issue with @apollo/client 3.0.0-beta.7. I'm running on react-native (expo) while connected to the React Native Debugger. If I disconnect from the debugger, I don't seem to have this issue. The version of React Native Debugger I'm using is 0.10.2. Perhaps this issue is with RND?

@AlbertMontolio
Copy link

I m getting the same problem locally. I can see the query has returned results in the chrome network tab:

Screenshot 2019-11-10 at 19 17 08

More over if I do this:

const link = new HttpLink({ uri: "https://localhost:4001/api" });
const cache = new InMemoryCache();
const client = new ApolloClient({ cache, link });
client
  .query({
    query: gql`
      {
        property {
          images {
            url
          }
        }
      }
    `,
  })
  .then((result) => console.log(result));

It also console logs what I would expect. However in the component, when using a hook:

  const { loading, error, data } = useQuery(IMAGE_QUERY, {
    notifyOnNetworkStatusChange: true,
  });
  
  console.log(data);
  console.log(error);
  console.log(loading);

Data is always undefined as is the error object, network status of 1. I would copy you the whole result of the useQuery but that seems impossible (can't stringify it as it's circular...)

I have exactly the same issue

@hamzakubba-opendoor
Copy link

hamzakubba-opendoor commented Dec 5, 2019

I found a workaround in 3.1.3, which is to set { pollInterval: 0 } as an option. Not sure why it fixes it, but seems to do so consistently for me.

@hyochan
Copy link

hyochan commented Dec 17, 2019

I am not sure either but when I've removed split, it started working.

// const link = split(
//   // split based on operation type
//   ({ query }) => {
//     const definition = getMainDefinition(query);
//     return (
//       definition.kind === 'OperationDefinition' &&
//       definition.operation === 'subscription'
//     );
//   },
//   // wsLink,
//   httpAuthLink,
// );

export default new ApolloClient({
  link: authLink.concat(httpLink),
  cache,
  resolvers,
});

@wintercounter
Copy link

wintercounter commented Jan 7, 2020

Same issue here. None of the above hacks seem to work for me. We tried refetch, forced rerender after a few seconds, not working. However setting notifyOnNetworkStatusChange: true made it work. Only Safari is affected for some reason.

@bulutfatih
Copy link

For a temporary solution, you can try to set fetchPolicy: 'no-cache'

@jesuslopezlugo
Copy link

I had the same issue on @apollo/react-hooks 3.1.3, this is my code with my workaround:

import React from "react";
import {FormattedMessage} from 'react-intl';
import {loader} from 'graphql.macro';
import {useQuery} from '@apollo/react-hooks';

const Workspace = () => {
    const GET_WORKSPACE = loader('./../../../graphql/Workspace/get_workspace.graphql');
    const {loading, error, data, refetch} = useQuery(
        GET_WORKSPACE,
        {
            variables: {user_id: "12345"},
            onCompleted: data => { }
        }
    );
    if (loading) return 'Loading...';
    if (error) return `Error! ${error.message}`;
    return (
        <div style={{padding: 24, background: '#fff', minHeight: 360}}>
            <h2><FormattedMessage id="dashboard.tasks.title" defaultMessage="Tasks"/></h2>
            {data.workspace.map(item => (
                <span key={item.id}> {item.name}</span>
            ))}
            <button onClick={() => refetch()}>Refetch!</button>
        </div>
    );
};

I found a solution of my infinite loop/loading stuck issue, just passing an empty function to onCompleted property of useQuery and problem solved 😕

I tried with fetchPolicy: 'no-cache' and pollInterval: 0 without sucess

@lxe
Copy link

lxe commented Apr 7, 2020

I'm seeing this at a very intermittent fashion. Happened on its own in production, then disappeared, then happened again. I'm guessing it's dependent on the response data/timing/headers, etc...?

What I was seeing is that both loading and data are set, and refetch policy was not honored, and it was rerunning the query/updating react state every n seconds.

I don't know if I'll be able to reproduce this.

@benjamn
Copy link
Member

benjamn commented Apr 7, 2020

I believe apollographql/apollo-client#6120, just released in @apollo/client@3.0.0-beta.43, may help with some of these problems.

@francisfueconcillo
Copy link

Got stuck for this in a while, but figured out watching for the data instead of the loading flag works for me.

@smeijer
Copy link

smeijer commented Apr 29, 2020

I'm having the same issue with apollo-client: 2.6.2 and react-apollo: 3.1.3. I have two components on my page, being rendered at the same time as they share a parent, and are rendered unconditionally. Both having the exact same useQuery call.

One of the components rerenders once loading is completed and shows the data. The other one does not.

I'm working around the issue by manually storing the result in local state:

function MyComponent() {
  const [data, setData] = useState(null);

  useQuery(DOCUMENT, {
    variables: { ... }
    onCompleted: (data) => setData(data);
  });

  return <>{JSON.stringify(data)}</>
}

@volkanunsal
Copy link

I have a similar problem. loading is set to false, but data is empty, even though the network tab shows the request was successful with a non-empty response.

@Fabchick
Copy link

same problem here.

@jongirard
Copy link

jongirard commented Jun 15, 2020

I was experiencing this problem which after some digging into my code ended up being caused by graphql.macro and using the loader inside my function.

const Car = () => {
const GET_CARS = loader('./../graphql/cars.graphql'); (Causes infinite loop)

Moving the const declaration of the query to the top of the file beneath the import {loader} from 'graphql.macro'; resolved the infinite loop/stuck loading query for me. Hopefully this helps someone in the future.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.