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

Query component empty data {} when refetching data #2114

Closed
andrepcg opened this issue Jun 15, 2018 · 29 comments
Closed

Query component empty data {} when refetching data #2114

andrepcg opened this issue Jun 15, 2018 · 29 comments

Comments

@andrepcg
Copy link

andrepcg commented Jun 15, 2018

I have a Project type that has various attributes and relations. One relation is Participations which relates a User to a Project.

When the page loads the entire project gets loaded using the following query:

GET_PROJECT

    project(id: $id) {
      id
      isFinished
      name
      startDate
      endDate
      organization {
        id
        types {
          id
          name
        }
      }
      client {
        id
      }
      participations {
        id
        type {
          id
          name
        }
        user {
          id
          email
          organizations {
            id
          }
        }
      }
    }

There's a sub component that updates the project Participations. This subcomponent uses refetchQueries (just for testing purposes) to update the participations list.

Refetch query (GET_PROJECT_PARTICIPATIONS)

    project(id: $id) {
      id
      participations {
        id
        type {
          id
          name
        }
        user {
          id
          email
        }
      }
    }

There's an issue with the data reconciliation in apollo because by using the following refetch query, the data object from the parent component (the one that has the entire Project query, GET_PROJECT) gets empty.

I've already debugged server responses, everything has an ID, no errors are popping anywhere, the last thing missing is something funky happening in Apollo. The Apollo cache get's correctly updated after the mutation and refetch query and the project is still there. Why then the data object from the GET_PROJECT Query components gets updated and it's now an empty object?

PS: I've already tested with network-only policies

Version

  • apollo-boost@0.1.9
  • react-apollo@2.1.5

More info

Parent component:

<Query
    query={GET_PROJECT}
    fetchPolicy="cache-and-network"
    variables={{ id: props.match.params.id }}
  >
    {Project(props)}
  </Query>

Inside Project component:

<Mutation
    refetchQueries={[
      {
        query: GET_PROJECT_PARTICIPATIONS,
        variables: { id: props.id },
      },
    ]}
    mutation={CREATE_PARTICIPATION}
  >
    {(mutate, result) => (
      (...)
    )}
  </Mutation>

const CREATE_PARTICIPATION = gql`
  mutation createParticipation($data: CreateParticipationInput!) {
    createParticipation(input: $data) {
      id
      user {
        id
      }
      type {
        id
        name
      }
    }
  }
`;

CREATE_PARTICIPATION response:
{"data":{"createParticipation":{"id":"57","user":{"id":"4","__typename":"User"},"type":null,"__typename":"Participation"}}}

GET_PROJECT_PARTICIPATIONS Response (refetch query):
{"data":{"project":{"id":"1","participations":[{"id":"54","type":{"id":"3","name":"Quality Assurance","__typename":"Type"},"user":{"id":"3","email":"marques@gmail.com","__typename":"User"},"__typename":"Participation"}],"__typename":"Project"}}}

@FranciscoMSM
Copy link

+1

@bensalilijames
Copy link
Contributor

I think there might be a problem with this line in apollo-client:

https://github.com/apollographql/apollo-client/blob/8b973216ab6fd41947e92cdf1ca3191f80465156/packages/apollo-client/src/core/QueryManager.ts#L984

It catches errors with "partial data" and reports back an empty object, but this sounds suspicious - it should throw/error properly if data can't be fulfilled. Anyway, that doesn't explain why it's partial data in the first place, which seems to be the inherent problem!

@ZwaarContrast
Copy link

Same issue with:

  • "apollo-cache-inmemory@1.1.5"
  • "apollo-client@2.3.5"
  • "apollo-link-context@1.0.3",
  • "apollo-link-error@1.1.0",
  • "apollo-link-http@1.3.2",
  • "react-apollo@2.1.6",

@MrSaints
Copy link

MrSaints commented Aug 13, 2018

I've just encountered this issue when performing an optimistic update against the cache. No data, and no errors / loading.

EDIT: resolved the issue by ensuring there's no "partial data" (Apollo warns you about them if you check your console).

@sebastianseilund
Copy link

Looks like this is related to / caused by apollographql/apollo-client#2920.

Work-around for me was to make sure two different queries (actually a query and a subscription) use the same fragment instead of using different/partial fields. Not optimal, but it made it work for now.

If you want to get a hint at what queries are causing this, try to add a breakpoint in apollo-client's QueryManager.ts' getCurrentQueryResult on the line inside the catch block. Inspect the error it catches. Note that multiple errors may be caught, and that maybe not all of them are the culprits.

@sebastiangrebe
Copy link

sebastiangrebe commented Nov 8, 2018

@sebastianseilund For me this happened in the exact same case.

I had one query which did request a list of chats like this:

{ 
    chats {
      id
      users {
        id
        avatar
        username
      }
      lastMessage {
        text
      }
    }
  }

The second query did the same but for exactly one chat by id.

query($chatId: Int!) {
    chat(chatId: $chatId) {
      id
      users {
        avatar
        username
      }
      messages {
        id
        text
        user {
            id
        }
      }
    }
  }

It did work before when I did not query for the users id in the first query. After adding the id to the first one but not in the second it just cleaned the cache. The fix for me was to also query the id for the users in the second query.
Furthermore this also applies for the mutation to send new messages.

@j0nd0n7
Copy link

j0nd0n7 commented Jan 5, 2019

I'm experiencing this issue with a Query and a Subscription that returns a sub set of the query fields.
The problem: When new data arrives from the subscription the data returned by the query turns undefined I also see the subscription's loading flag always true.
It only happens if the sub set includes a nested type with and id (so it is cached individually in the store). If I remove from the subscriptions fields this nested type, everything works fine.

To fetch data I'm using both Query and Subscription Components

Query fields:

 {
      id
      state
      fieldA
      fieldB
      fieldC
      ...
      nested {
         id
         name
      }
}

Subscription fields:

 {
      id
      state
      nested {
         id
         name
      }
}

Dependency versions

"apollo-cache-inmemory": "^1.3.12",
"apollo-client": "^2.4.8",
"apollo-link-http": "^1.5.9",
"apollo-link-ws": "^1.0.12",
"react-apollo": "^2.3.3",
"graphql": "^14.0.2",

@grylance
Copy link

grylance commented Feb 20, 2019

I was encountering this issue when two simultaneous queries were requesting difference fields from the same items. I solved the problem by creating a fragment for both queries to use to make sure the fields for both for the item in question were exactly the same.

@yaronya
Copy link

yaronya commented Mar 28, 2019

I was also experiencing this when the shape of a mutation is different from the shape of my initial query.
I would've expected that the it will return an "error" object and not just clear the "data" object.

Is this a bug or a feature? couldn't find anything about it in the docs though...

@mehmetnyarar
Copy link

I'm also encountering this issue.

My layout component has <Query variables={{ id }} /> which queries all the data related to an item, and I have 4 children underneath, each has <Mutation /> which updates a section of an item.

After mutating the data, Query returns {}.

@lucaschen
Copy link

Same issue here.

Perhaps I'm not understanding something, but isn't the optimal solution here for React Apollo to trigger a re-fetch of the original query, hence causing a completely updated copy of the dataset?

I'm currently getting data equal to {}, and loading being false, and also no error - this doesn't play well within my app. 😐

@jonerer
Copy link

jonerer commented May 11, 2019

@parkroolucas You can enable that behaviour by setting "partialRefetch={true}" on the failing Query. Agreed, the error state is really bad for this bug.

@drixta
Copy link

drixta commented May 15, 2019

I'm having the same issue. I'm making a Mutation request on a completely different object and pretty much every Query component are returning data equal to {}

@simPod
Copy link

simPod commented May 15, 2019

Also check that your query and mutation query the same data (the best is to use fragment ofc).

I had some fields missing in my mutation payload and it was giving {} for original query. Which was very consfusing given there was no error message at all.

@hwillson
Copy link
Member

The returnPartialData functionality added in react-apollo 2.5.6 will help here. Please see the release notes for more details. Thanks!

@lucaschen
Copy link

@hwilson I just tried using it, however returnPartialData doesn't solve my problem at all.

Let's say I have a query like so:

query {
  users {
    id
    images {
      id
      image32
      image48
    }
  }
}

And say I have a mutation like so:

mutation {
  updateUser(id: 1, doSomethingTo: "image-2") {
    id
    images {
      id
      image32
      # image48 not included here
    }
  }
}

Now if I were to run the mutation on a component and then re-load the query component, one of two things will happen:

  1. If I don't use returnPartialData, I will get the following:

    {
      data: {},
      error: undefined,
      loading: false
    }
  2. If I use returnPartialData, I will get the following:

    {
      data: {
        users: [
          {
            id: "1",
            images: [
              {
                id: "image-1",
                image32: "image32.png",
                image48: "image48.png"
              },
              {
                id: "image-2",
                image32: "image32.png"
                // image48 gets excluded here
              }
            ]
          }
        ]
      }
    }

This isn't what I expect to have happen. Shouldn't the query component realise that it doesn't have sufficient data, and in response re-run the fetching query?

@lukaskl
Copy link

lukaskl commented Jul 10, 2019

I believe this ticket was closed too early.
There are valid cases, when we don't want to handle partial data.
And what @parkroolucas suggested seems like a reasonable thing to expect:

This isn't what I expect to have happen. Shouldn't the query component realise that it doesn't have sufficient data, and in response re-run the fetching query?

@migueloller
Copy link

I agree with @parkroolucas. It could be handled like a fetchMore call, where loading stays true, the data reflects the currently cached value, excluding the new partial data from the mutation, while the query is re-fetched.

So with returnPartialData set to false, the result would be as follows:

{
  loading: true,
  data: {
    users: [
      {
        id: "1",
        images: [
          {
            id: "image-1",
            image32: "image32.png",
            image48: "image48.png"
          },
          // Partial result from mutation isn't included as it doesn't have all required fields.
        ]
      }
    ]
  }
}
{
  loading: false,
  data: {
    users: [
      {
        id: "1",
        images: [
          {
            id: "image-1",
            image32: "image32.png",
            image48: "image48.png"
          },
          {
            id: "image-2",
            image32: "image32.png"
            image48: "image48.png"
          }
        ]
      }
    ]
  }
}

Instead of the pesky empty data object.

@hwillson would you consider reopening this issue?

@lucaschen
Copy link

Bump because I can't believe that there is no real solution to this seemingly fundamental issue 🤷‍♂️

@sgup
Copy link

sgup commented Sep 20, 2019

I had some similiar data loading issues, were resolved by updating all apollo / react packages to latest version. Especially react-apollo, probably.

@lucaschen
Copy link

@sgup Could you please clarify what existing data loading issues you had, and updating to which specific version(s) resolved your issue? Just in case you accidentally lead someone down a false positive path.

@sgup
Copy link

sgup commented Sep 25, 2019

@parkroolucas Unfortunately I don't remember exactly. I was trying to implement SSR, and the data was coming back as {} in my Query components.

Looking at my commits, I changed from apollo-boost to apollo-client and updated all the apollo-related libraries to the latest version.

@qeternity
Copy link

qeternity commented Oct 1, 2019

Bump because I can't believe that there is no real solution to this seemingly fundamental issue 🤷‍♂️

It's really unbelievable. It makes me wonder what sort of people are running around on Apollo's engineering team.

@hwillson please can we reopen this

@qeternity
Copy link

@parkroolucas so I think I just got to the bottom of this, it appears to be an issue in react-apollo <= 2.5.6 and I believe it was inadvertently fixed in this commit: 2b7073b

Hilariously, the perma-loading error that was fixed in this commit is something we'd actually engineered around, so we didn't bother upgrading. Using 2.5.8 now this all seems fixed.

@bernhardt1
Copy link

@qeternity I'm still seeing this issue in 2.5.8

@groovepack
Copy link

Hi - i have the same issue with 2.6.8 in combination with graphcms-Backend. I get a list of urls and then pop the entries. If the array is empty i fetch again and the data-node is empty ...

using

"apollo-cache-inmemory": "^1.6.5",
"apollo-client": "^2.6.8",
"apollo-link-http": "^1.5.16",
"graphql": "^14.5.8",
"graphql-tag": "^2.10.1",

@qeternity
Copy link

@qeternity I'm still seeing this issue in 2.5.8

We've upgraded to v3 and haven't had any issues. Perhaps something to consider.

@mkonicek
Copy link

mkonicek commented Jun 12, 2020

Upgrading fixed the bug for me:

"apollo": "^2.28.3"

previously I was on 2.25.0 and had this bug.

While at it, I also upgraded a bunch of other libraries:

"apollo": "^2.28.3",
"@apollo/react-hooks": "^3.1.5",
"apollo-cache-inmemory": "^1.6.6",
"apollo-client": "^2.6.10",
"apollo-link": "^1.2.14",
"apollo-utilities": "^1.3.4",
"react-apollo": "^3.1.5"

@renepardon
Copy link

I'm using the following packages:

"apollo": "^2.28.3",
"apollo-utilities": "^1.3.4",
"apollo-boost": "^0.4.9",
"apollo-cache": "^1.3.5",
"apollo-client": "^2.6.10",
"apollo-link": "^1.2.14",
"apollo-link-http": "^1.5.17",

My "solution" is to set fetchPolicy for the request:

const {
    data,
    loading: mediumLoading
} = useQuery(GET_MEDIUM_QUERY, {variables: {id: props.match.params.id}, fetchPolicy: "no-cache"})

My JSX body looks like: (shortened)

{mediumLoading && <Loading loading={mediumLoading}/>}
{data && <span>Medium detail page for uuid <strong>{data.getMedium.uuid}</strong> goes here</span>}

The problem? If I reload the page or use fetchPolicy with no-cache option, everything works as expected. If I navigate to the corresponding page by clicking a react router link, the data is fetched properly (network tab as a proof) but data is either not defined or empty

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

No branches or pull requests