I started with apollo-client on a new app, but switched to using ngrx and turning off apollo-client caching (basically using apollo-client as a fancy graphql request library - I should probably just use apollo-link directly). My main problem was that it felt like it required both developers and components to have too much knowledge of the individual queries that the app was making. Instead of writing an app that happened to use graphql, I felt like I was writing a graphql app.
An example of that is updating the state after mutations that modify lists (e.g. creates or deletes). It's up to the developer to remember all other queries that could be affected by a mutation and to update them manually after the mutation completes (more info: https://github.com/apollographql/apollo-client/issues/3505 and https://www.apollographql.com/docs/angular/features/cache-up...). If you add a new component that performs
a query that could be affected by a previous mutation, you have to remember to also go back to that mutation and update your query from it. With ngrx (or redux), the consistency is baked in, and part of the beauty of it is that if you update the state, anyone who happens to be reading that state will get updated automatically.
I can see where updating the cache in all the right places for complex architectures could get hairy. For my own personal project, I'm using GraphQL Subscriptions to listen for mutations and piping those events directly to the client, which then updates the cache accordingly. I get that's not a solution for everyone as it would largely depend on your backend architecture having support for subscriptions.
Not negative as such, just didn't hit the mark that their marketing material was promising.
It's great for pull down refresh lists etc and I even had success doing dynamic insertion when an item in another view was updated (though I had to use a different graphql client to do the inserts ironically) but it was sold as replacing all need for redux for example for state management and that it would sync seamlessly with a graphql backend and unfortunately (maybe it was me) couldn't work out how to do that so ended up using redux as well.
What I was lead to expect is that you subscribe to a store which is dynamically filled and updated by Apollo (which handles synchronising local and remote and loading from scratch etc).
It might have had to do with the fetchPolicy that was in place. By default, Apollo aggressively uses local caching. But this is not always good. Ideally you could just subscribe to GraphQL subscriptions which would update your local stores, but I understand not all backend architectures are wired up that way. https://www.apollographql.com/docs/react/advanced/caching.ht...
Apollo has more advanced configuration options, and I think they're confusing to grasp at first. But I do think Apollo cuts down on the amount of state management you need to do for a typical app by about 2/3rds or more.
An example of that is updating the state after mutations that modify lists (e.g. creates or deletes). It's up to the developer to remember all other queries that could be affected by a mutation and to update them manually after the mutation completes (more info: https://github.com/apollographql/apollo-client/issues/3505 and https://www.apollographql.com/docs/angular/features/cache-up...). If you add a new component that performs a query that could be affected by a previous mutation, you have to remember to also go back to that mutation and update your query from it. With ngrx (or redux), the consistency is baked in, and part of the beauty of it is that if you update the state, anyone who happens to be reading that state will get updated automatically.