Apollo Link State配置异常:查询返回空对象求助
Let's work through your issues with Apollo Link State—first the 400 error, then the empty query response, and finally why removing defaults breaks query recognition. I've dealt with these exact pitfalls before, so let's dive in.
First: Why You Got the 400 Status Code
That initial 400 error almost always means your local query was being sent to your remote GraphQL server instead of being handled by Apollo Link State. Here's why that happens:
- Link order is wrong: The
stateLink(fromwithClientState) needs to come before yourhttpLinkin the Apollo Link chain. If you puthttpLinkfirst, Apollo sends every query to the remote server, which has no clue what your@client-annotatednetworkStatusfield is. - Missing typeDefs: If you didn't define the
networkStatusfield in your local schema, Link State doesn't recognize the query as local, so it passes it along to the remote server.
Next: Why the Query Returns an Empty Object
After fixing the 400, getting an empty object usually boils down to a missing __typename or misaligned cache structure. Apollo Cache relies heavily on __typename to map data to your schema. Here are the common fixes:
1. Ensure defaults Includes __typename
Your default state needs to explicitly include the type name for the networkStatus object. Without it, Apollo can't find the data in the cache. For example:
const defaults = { networkStatus: { __typename: 'NetworkStatus', // This is critical! isConnected: true } };
2. Verify Your Local Schema (typeDefs)
Double-check that your typeDefs correctly defines the NetworkStatus type and the networkStatus query field:
const typeDefs = ` type NetworkStatus { isConnected: Boolean! } type Query { networkStatus: NetworkStatus! } `;
If the field names or types don't match your query (e.g., spelling isConnected wrong), Apollo won't return data.
3. Check Resolver Logic (If You're Using One)
If you added a resolver for networkStatus, make sure it's correctly reading from the cache. A common mistake is not falling back to the default state if the cache is empty:
const resolvers = { Query: { networkStatus: (_, __, { cache }) => { // Try reading from cache first const cachedData = cache.readQuery({ query: gql`{ networkStatus @client { isConnected } }` }); // Fall back to defaults if nothing is cached return cachedData?.networkStatus || defaults.networkStatus; } } };
If you don't have a resolver, Apollo will automatically read from the cache—so getting the defaults structure right is even more important.
Why Removing defaults Breaks Query Recognition
When you remove defaults, Apollo Link State still recognizes the query (thanks to typeDefs), but there's no initial data in the cache, and if you don't have a resolver that returns a value, it will return null or an empty object. Wait, but you said the query "can't be recognized"—that probably means your typeDefs wasn't properly linked to the client. Make sure you're passing typeDefs to withClientState and that the client is using the combined link chain.
Full Working Setup Example
Let's put it all together with a correct configuration to avoid these issues:
import { ApolloClient, InMemoryCache, HttpLink, ApolloLink, gql } from '@apollo/client'; import { withClientState } from 'apollo-link-state'; // 1. Define your local schema const typeDefs = ` type NetworkStatus { isConnected: Boolean! } type Query { networkStatus: NetworkStatus! } # Optional: Mutation to update network status later type Mutation { updateNetworkStatus(isConnected: Boolean!): Boolean } `; // 2. Set initial state with __typename const defaults = { networkStatus: { __typename: 'NetworkStatus', isConnected: navigator.onLine // Use browser's online status as initial value } }; // 3. Add resolvers (optional but useful for updates) const resolvers = { Mutation: { updateNetworkStatus: (_, { isConnected }, { cache }) => { cache.writeData({ data: { networkStatus: { __typename: 'NetworkStatus', isConnected } } }); return isConnected; } } }; // 4. Configure links in the correct order const httpLink = new HttpLink({ uri: '/your-graphql-endpoint' }); const cache = new InMemoryCache(); const stateLink = withClientState({ cache, defaults, typeDefs, resolvers }); // State link first, then HTTP link const client = new ApolloClient({ link: ApolloLink.from([stateLink, httpLink]), cache }); // 5. Define your query const GET_NETWORK_STATUS = gql` query GetNetworkStatus { networkStatus @client { isConnected } } `; // Test the query client.query({ query: GET_NETWORK_STATUS }) .then(result => console.log('Network status:', result.data.networkStatus)) .catch(err => console.error('Query error:', err));
Quick Troubleshooting Checklist
- Confirm
stateLinkis beforehttpLinkin the link chain. - Check that
defaultsincludes__typenamefor all objects. - Verify
typeDefsmatches your query's fields and types. - Test manually writing to the cache with
client.writeData()to see if the query picks up the change. - Ensure your Apollo Client and
apollo-link-stateversions are compatible (older versions might have different API behavior).
内容的提问来源于stack exchange,提问作者Evanss

