-
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
Apollo Client local state #4155
Conversation
- apollo-boost@0.1.17-local-state-alpha.0 - apollo-cache-inmemory@1.3.1-local-state-alpha.0 - apollo-cache@1.1.18-local-state-alpha.0 - apollo-client@2.4.3-local-state-alpha.0 - apollo-utilities@1.0.22-local-state-alpha.0 - graphql-anywhere@4.1.20-local-state-alpha.0
- apollo-boost@0.1.17-local-state-alpha.1 - apollo-cache-inmemory@1.3.1-local-state-alpha.1 - apollo-cache@1.1.18-local-state-alpha.1 - apollo-client@2.4.3-local-state-alpha.1 - apollo-utilities@1.0.22-local-state-alpha.1 - graphql-anywhere@4.1.20-local-state-alpha.1
- apollo-boost@0.1.17-local-state-alpha.2 - apollo-cache-inmemory@1.3.1-local-state-alpha.2 - apollo-cache@1.1.18-local-state-alpha.2 - apollo-client@2.4.3-local-state-alpha.2 - apollo-utilities@1.0.22-local-state-alpha.2 - graphql-anywhere@4.1.20-local-state-alpha.2
- apollo-boost@0.1.17-local-state-alpha.3 - apollo-cache-inmemory@1.3.1-local-state-alpha.3 - apollo-cache@1.1.18-local-state-alpha.3 - apollo-client@2.4.3-local-state-alpha.3 - apollo-utilities@1.0.22-local-state-alpha.3 - graphql-anywhere@4.1.20-local-state-alpha.3
We want to make sure brand new initializer functions, that are associated with a field that is already in the initializer list, can be overwritten by new initializer functions.
- apollo-boost@0.1.17-local-state-alpha.4 - apollo-cache-inmemory@1.3.1-local-state-alpha.4 - apollo-cache@1.1.18-local-state-alpha.4 - apollo-client@2.4.3-local-state-alpha.4 - apollo-utilities@1.0.22-local-state-alpha.4 - graphql-anywhere@4.1.20-local-state-alpha.4
The `graphql-async` rollup config is currently doing strange things in the local state alpha. The plan is to completely replace the current non-async version of `graphql` with the async version, which will fix this issue. Until this happens, we'll push a sync `graphql` version alongside the async `graphqlAsync` version, to let alpha testing continue.
- apollo-boost@0.1.17-local-state-alpha.5 - apollo-cache-inmemory@1.3.1-local-state-alpha.5 - apollo-cache@1.1.18-local-state-alpha.5 - apollo-client@2.4.3-local-state-alpha.5 - apollo-utilities@1.0.22-local-state-alpha.5 - graphql-anywhere@4.1.20-local-state-alpha.5
- apollo-boost@0.1.17-local-state-alpha.6 - apollo-cache-inmemory@1.3.1-local-state-alpha.6 - apollo-cache@1.1.18-local-state-alpha.6 - apollo-client@2.4.3-local-state-alpha.6 - apollo-utilities@1.0.22-local-state-alpha.6 - graphql-anywhere@4.1.20-local-state-alpha.6
- apollo-boost@0.1.17-local-state-alpha.7 - apollo-cache-inmemory@1.3.1-local-state-alpha.7 - apollo-cache@1.1.18-local-state-alpha.7 - apollo-client@2.4.3-local-state-alpha.7 - apollo-utilities@1.0.22-local-state-alpha.7 - graphql-anywhere@4.1.20-local-state-alpha.7
The graphql-anywhere `graphql` function used by local resolvers is async, which means we need to make sure it has completed, before finalizing the fetchRequest observable subscriber function. Otherwise, the observable can be marked as complete, while local resolver data is still coming in (and will then be dropped).
- apollo-boost@0.1.17-local-state-alpha.8 - apollo-cache-inmemory@1.3.1-local-state-alpha.8 - apollo-cache@1.1.18-local-state-alpha.8 - apollo-client@2.4.3-local-state-alpha.8 - apollo-utilities@1.0.22-local-state-alpha.8 - graphql-anywhere@4.1.20-local-state-alpha.8
Change focus from initializing the store with defaults to accommodate local state handling, to a more broad and flexible store initialization strategy, that can be used outside of local state handling. This commit: - Renames across the board to accommodate the newer store initialization approach - Moves store initialization into `ApolloClient` - Makes sure store initializer functions get access to the current `ApolloClient` instance
Data loaded from the cache using `@client` can now be stored in a variable, and that variable can then be used in associated queries. For exammple: ``` query topPosts($postIds: [Int]!) { topPosts @client(as: "postIds") posts(ids: $postIds) { title votes } } ``` Top post IDs are loaded from the cache, and made available to the `posts` query as the `postIds` variable.
We don't really need to store the full store initializer functions. We just need a way of making sure initializers are only run once. We can do this by just tracking the field name associated with the initializer. In the future we might want to store full initializer functions, to say re-trigger them automatically after a `resetStore` call, but this could prove to be more hassle than its worth. Re-triggering initializer functions can always be handled in userland after a `resetStore` (using `onResetStore`). Also, if certain initializers are triggered via certain code split paths, then re-triggering that initializer again automatically in a different part of the application could be tricky/dangerous. This commit also moves the bulk of the initializer handling out of the main AC class, storing it alongside the `DataStore` it's impacting.
- apollo-boost@0.1.17-local-state-alpha.9 - apollo-cache-inmemory@1.3.1-local-state-alpha.9 - apollo-cache@1.1.18-local-state-alpha.9 - apollo-client@2.4.3-local-state-alpha.9 - apollo-utilities@1.0.22-local-state-alpha.9 - graphql-anywhere@4.1.20-local-state-alpha.9
- apollo-boost@0.3.0-alpha.11 - apollo-cache-inmemory@1.4.0-alpha.11 - apollo-client@2.5.0-alpha.9
This commit updates the `apollo-utilities` transformation `nullIfDocIsEmpty` helper function to handle both `OperationDefinition`'s and `FragmentDefinition`'s.
- apollo-boost@0.3.0-alpha.12 - apollo-cache-inmemory@1.4.0-alpha.12 - apollo-cache@1.2.0-alpha.9 - apollo-client@2.5.0-alpha.10 - apollo-utilities@1.1.0-alpha.10 - graphql-anywhere@4.2.0-alpha.9
Just a quick note about the bundle size increase here - it's temporary, and will be pruned down shortly. |
…graphql/apollo-client into hwillson/link-state-merge
@hwillson fyi - I'm trying this locally in react-native and the data turns undefined unless I initialize it myself before querying, i.e. the tutorial online did not have setup intructions but from looking at PR, pretty sure im passing the options correctly so not sure why the initializers aren't working
also, will initializers support async functions? It'll be necessary in order for the |
another issue Im seeing is that for the first query, the data is not available and returns an empty object first and then the result, i.e. (if you're not seeking early testing right now, apologies and ignore these comments!) |
@alidcastano We're definitely seeking feedback, so thanks for this! Initializers called during Regarding initializers supporting async, they do currently, but not via the const client = new ApolloClient({ ... });
...
client.runInitializers(async () => {
await someFunction();
...
}); |
hmm for some reason the intializers weren't working before but now they are 👍 in regards to the async functions, passing a function to but I was able to get it working using the following code
(^^ I'm guessing we don't need to pass the initializes as a constructor option if we're running them ourselves) my project is a react native app and a server-rendered web app (using react-native-web), so i can confirm in works on both environments! |
FYI we just cut over to try this out, seems to be working fine! Using SSR and web client-side (for PWA support) |
Quick note - this PR has been replaced by #4338. We'll continue the discussion there. Thanks! |
In a nutshell, this PR migrates the local state handling capabilities provided by
apollo-link-state
, into the Apollo Client core.@client
directive handling is fully managed by Apollo Client (through theQueryManager
), without requiring a separate Apollo Link.While opinionated, these changes are being considered to help address several outstanding
apollo-link-state
issues that are difficult to address in a link chain, and open the door to future Apollo Client changes that integrate local state handling more closely with the Apollo Cache.The implementation outlined in this PR closely mirrors existing
apollo-link-state
functionality, with a few changes / additions to make handling local state with Apollo Client more flexible and easy to use.Key Changes
It is no longer necessary to add
apollo-link-state
to your link chain. Apollo Client includes all local state functionality out of the box.The idea of initializing your local cache with
apollo-link-state
's fixeddefaults
option has been replaced with a newinitializer
function approach. Initializers are simple functions, that can be run duringApolloClient
instantiation, or via theApolloClient.runInitializers
function. These functions are mapped against the name of the field you want to update in the cache, and the result of running the function is stored in the cache against that field. Initializers can be as flexible as you need them to be, and can either write the returned result directly to the cache, or be configured to skip writing to the cache, letting you handle that manually inside the initializer function yourself. Each initializer function is called with access to theApolloClient
instance, so the full AC API is available.Initializers do not check to see if they'll overwrite existing data when run. For now we're avoiding the extra cache hit of having initializers check to see if data already exists for a field, before overwriting it. This functionality can be overwritten by manually checking and updating the cache yourself in an initializer function.
Initializers are only run once (to help prevent overwriting data accidentally).
Local resolvers can be set through the
ApolloClient
resolvers
constructor param, or by calling theApolloClient.addResolvers
function.A local schema can be defined by passing it into the
ApolloClient
constructor via thetypeDefs
parameter.Mixing remote and local fields together in queries / selection sets (aka virtual fields) is still supported, along with some additional features.
@client ... @export(as: "someVar")
can now be used to pass the result of a locally resolved query in as a variable for a remote query, all in the same request. For example:Subscriptions now recognize the
@client
directive, meaning locally resolved data can be combined with incoming subscription data.Full SSR support.
Numerous bug fixes and changes made to address outstanding
apollo-link-state
issues (issues labelled asac-local-state-ready
are fixed by these changes).And more! 🙂
This PR is still a work in progress (and is not ready for review), but we're pushing hard to get it wrapped up soon.
TODO:
Documentation. This PR is already getting pretty large, so I'll submit the updated local state docs in a separate PR.