-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Under-fetching fields of new objects in mutations silently breaks mounted Queries #3267
Comments
I've had similar observations when upgrading from 2.0 to 2.1. When 2 queries that fetch the same node but with different fields run in sequence, the second query initially renders a partial node but with missing fields, instead of presenting the previous behavior of rendering For example, when you have the following 2 queries: query Profile($id: GUID!) {
profile(id: $id) {
id
firstName
lastName
}
}
query ProfileWithFields($id: GUID!) {
profile(id: $id) {
id
firstName
lastName
fields {
name
value
}
}
} The second query will initially be rendered with profile: {
id: 123,
firstName: 'John',
lastName: 'Doe',
fields: undefined
} whereas before it would initially have rendered with In our case this is a little bit problematic since we're not checking loading states but rather whether I haven't had time yet to dig into or set up a repro for this and reverted back to 2.0 for now but I have a suspicion it might be related to the subject of this issue. |
As an aside, I think this is caused by |
I have similar problems since upgrade. So far I try to add guards to my code, which is ugly as you can guess, so I would appreciate if this issue gets higher priority. |
We encountered the same issue. |
Hey, as our issue with optimisticResponses might be very much related, I am posting this here. We reproduced our issue https://github.com/whootor/react-apollo-error-template/tree/optimist. Example 1
At
Another issue that arises in Example 3 is that the mutation response is overwritten by the fully fetched query response with old data. As the mutation was triggered after the full query was, it should have precedence before the full query and be merged on top of the full query. We believe to have traced down the issue to the merging in the in-memory-cache, but didn't get any further so far. |
Also ran into this behavior today after upgrading |
Can report I am having the same issue as well, possibly related to apollographql/react-apollo#1314 ? |
Seems related: #2920 (comment) |
To workaround this bug unitl it's fixed, I've used this ugly hack and has worked so far: shouldComponentUpdate ({ data }) {
if (data && !data.loading && !data.error && !data.dataYouWereExpecting) {
data.refetch()
return false
}
return true
} Simply refetch the query if it became broken and prevent buggy renders and flashes while it refetches. |
@stefanmaric I have a fix for this. Will open a PR soon Edit: Fix is up in apollographql/react-apollo#2003 |
I just spend about two days trying to nail this issue down. Extremely infuriating. Great to hear that a fix is on the way! |
(Also posted on apollographql/react-apollo#2003) No action on this issue so far. 😞 import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloClient } from "apollo-client";
import { ApolloLink } from "apollo-link";
import { SchemaLink } from "apollo-link-schema";
import Promise from "bluebird";
import { assert } from "chai";
import { mount } from "enzyme";
import gql from "graphql-tag";
import { makeExecutableSchema } from "graphql-tools";
import React from "react";
import { ApolloProvider, Query } from "react-apollo";
describe("Cache-And-Network", () => {
function createTestSchema() {
const typeDefs = `
type Query {
foo: Foo!
}
type Foo {
id: ID!
field1: String
field2: String
}
`;
const resolvers = {
Query: {
async foo() {
return {
id: "id5",
field1: "value1",
field2: "value2"
};
}
}
};
return makeExecutableSchema({ typeDefs, resolvers });
}
const schema = createTestSchema();
const link = ApolloLink.from([new SchemaLink({ schema })]);
const apolloCache = new InMemoryCache();
const client = new ApolloClient({
cache: apolloCache,
link
});
function FooView({ id, field1, field2, bar = {} } = {}) {
return <div>{[id, field1, field2, bar].join(" ")}</div>;
}
class Parent extends React.Component {
state = { show: "A" };
render() {
const { show } = this.state;
if (show === "A") {
return (
<React.Fragment>
<a onClick={() => this.setState({ show: "B" })} />
<Query
query={gql`
query A {
foo {
id
field1
}
}
`}
>
{({ loading, data }) =>
loading ? null : <FooView {...data.foo} />
}
</Query>
</React.Fragment>
);
} else if (show === "B") {
return (
<React.Fragment>
<Query
query={gql`
query A {
foo {
id
field1
}
}
`}
>
{() => {
return null;
}}
</Query>
<Query
fetchPolicy="cache-and-network"
query={gql`
query B {
foo {
id
field1
field2
}
}
`}
>
{({ data }) => {
return !data.foo ? null : <FooView {...data.foo} />;
}}
</Query>
</React.Fragment>
);
}
}
}
it("should not return data.foo unless all fields are resolved from backend", async () => {
const app = mount(
<ApolloProvider client={client}>
<Parent />
</ApolloProvider>
);
await waitUntil(() => {
app.update();
return app.find(FooView).exists();
});
assert.deepEqual(app.find(FooView).props(), {
id: "id5",
field1: "value1",
__typename: "Foo"
});
app.find("a").simulate("click");
app.update();
await waitUntil(() => {
app.update();
return app.find(FooView).exists();
});
assert.deepEqual(app.find(FooView).props(), {
id: "id5",
field1: "value1",
field2: "value2",
__typename: "Foo"
});
});
});
async function waitUntil(checkFn, timeout = 2000, errorMessage) {
const start = new Date();
while (!checkFn()) {
await Promise.delay(10);
if (new Date() - start > timeout) {
throw new Error(errorMessage || "Timeout");
}
}
} |
Wanne add my experience as-well in the hope the issues might be picket up or get a higher prio. I'm building a relative large application and constantly hit problem with the cache. |
The first reports of this issue date from almost a year ago, there's a repro (#3267), there's an outstanding PR, but other than that there's very little to no info and no acknowledgement that this is being looked at, or that additional help is needed. I fully understand that this is an open-source project and I absolutely massively appreciate the efforts of the people involved, but the lack of communication on this (in my opinion, very severe) issue is slowly getting a bit frustrating. It feels like efforts are being focused elsewhere, which is fine of course, but I guess it would be nice to know if that's the case. Apollo-client and react-apollo are a core component of my (and many other people's) apps but I'm getting a little bit uncomfortable using it again for any new ones. |
@pleunv We know this is frustrating, and it's something we're looking into resolving in Apollo Client 3.0. The changes to fix this will likely be breaking, which is why it's going to be slotted into the next major release. In the meantime, we recommend people use something like AC's In the meantime, I'm very tempted to merge apollographql/react-apollo#2003 to help with this. It's not a perfect solution, but it does work. Would merging that PR help in your case? |
@hwillson I appreciate the response. In my case however (and others, as well as the example above) this behavior is not necessarily triggered by the use of I'll give the PR a shot (@steelbrain, you don't have this published to npm by any chance?) but looking at the code the fix seems to be directly in Due to the caching issue we're unable to upgrade to 2.0, which means that we're still using the HoC approach. Besides that, refactoring to |
The HOC's are now using |
re @pleunv: I've published v2.1.11 version of this package with the patch applied to |
@steelbrain And everything has been working well? @pleunv Can you try with |
Yes, everything has been working well in regards to this bug. But we have been working with a separate similar bug where Usually happens when a large number of queries is invoked in a short amount of time (think logout of app and all mounted react components have their redux state changed and do new gql requests and get unauthorized gql errors). The way we have "fixed" it in our app for now is with the assumption that in the GraphQL syntax, it's invalid to have a query with no fields, so in any case, regardless of |
Squeezed in some preliminary testing with @steelbrain's version and I'm not able to reproduce the underfetching issue! Will keep using it for the next few days because I think some more testing will be needed, and let you guys know if we do run into any problems. I'm really glad this is moving forward! I know you guys are juggling a lot of different projects and keeping a business running at the same time, and I really do appreciate all the time you put into this. Out of curiousity (mainly since you already mention 3.0): is there any public roadmap available, or is this still being discussed behind closed doors? :) |
@pleunv We're still hashing out the roadmap; it will be ready very soon, and will be referenced from apollographql/apollo-feature-requests#33. |
Intended outcome:
When a mounted query can not resolve its data from the cache, as in the case following an under-fetching mutation, (linked example app below), I would expect it to re-fetch.
Actual outcome:
The query does not re-fetch, but instead renders with
data: {}
. In a real application, the component will likely attempt to access properties ofundefined
, causing a crash.How to reproduce the issue:

Error template app here: https://github.com/stevehollaar/react-apollo-error-template/tree/mutate-bug
There are 2 mutation buttons, each which create a new
Pet
object and assign it to a random person.Pet
object to the cache, and successfully re-rendering the query inApp
.species
field. This still adds a newPet
object to the cache, but theApp
query is not satisfied, and renders withdata: {}
https://github.com/stevehollaar/react-apollo-error-template/blob/mutate-bug/src/MutateButton.js
Version
The text was updated successfully, but these errors were encountered: