Docs
Launch GraphOS Studio

Using GraphQL directives in Apollo Client

Configure GraphQL fields and fragments


A decorates part of a or with additional configuration. Tools like can read a GraphQL 's directives and perform custom logic as appropriate.

are preceded by the @ character, like so:

query myQuery($someTest: Boolean) {
experimentalField @skip(if: $someTest)
}

This example shows the @skip directive, which is a built-in directive (i.e., it's part of the

). It demonstrates the following about :

  • Directives can take of their own (if in this case).
  • Directives appear after the declaration of what they decorate (the experimentalField in this case).

@client

The @client directive allows you to resolve client-only data alongside your server data. These are not sent to the .

query LaunchDetails($launchId: ID!) {
launch(id: $launchId) {
site
rocket {
type
# resolved locally on the client,
# removed from the request to the server
description @client
}
}
}

For more information about the @client directive, see this section on

. The @client directive is also useful for
client schema mocking
before a given field is supported in the API your application is consuming.

@connection

The @connection directive allows you to specify a custom cache key for paginated results. For more information, see this section on the

.

query Feed($offset: Int, $limit: Int) {
feed(offset: $offset, limit: $limit) @connection(key: "feed") {
...FeedFields
}
}

@defer

Beginning with version 3.7.0, Apollo Client provides preview support for

. This directive enables your queries to receive data for specific fields incrementally, instead of receiving all field data at the same time. This is helpful whenever some fields in a take much longer to resolve than others.

To use the @defer directive, we apply it to an inline or named that contains all slow-resolving fields:

query PersonQuery($personId: ID!) {
person(id: $personId) {
# Basic fields (fast)
id
firstName
lastName
# Friend fields (slower)
... @defer {
friends {
id
}
}
}
}

Note: in order to use @defer in a React Native application, additional configuration is required. See the

for more information.

For more information about the @defer directive, check out the

.

@export

If your GraphQL query uses , the local-only fields of that query can provide the values of those variables.

To do so, you apply the @export(as: "variableName") directive, like so:

const GET_CURRENT_AUTHOR_POST_COUNT = gql`
query CurrentAuthorPostCount($authorId: Int!) {
currentAuthorId @client @export(as: "authorId")
postCount(authorId: $authorId)
}
`;

In the query above, the result of the local-only field currentAuthorId is used as the value of the $authorId that's passed to postCount.

You can do this even if postCount is also a local-only field (i.e., if it's also marked as @client).

For more information and other considerations when using the @export directive, check out the

.

@nonreactive
Since 3.8.0

The @nonreactive directive can be used to mark query fields or fragment spreads and is used to indicate that changes to the data contained within the subtrees marked @nonreactive should not trigger rerendering. This allows parent components to fetch data to be rendered by their children without rerendering themselves when the data corresponding with fields marked as @nonreactive change.

Consider an App component that fetches and renders a list of ski trails:

const TrailFragment = gql`
fragment TrailFragment on Trail {
name
status
}
`;
const ALL_TRAILS = gql`
query allTrails {
allTrails {
id
...TrailFragment @nonreactive
}
}
${TrailFragment}
`;
function App() {
const { data, loading } = useQuery(ALL_TRAILS);
return (
<main>
<h2>Ski Trails</h2>
<ul>
{data?.trails.map((trail) => (
<Trail key={trail.id} id={trail.id} />
))}
</ul>
</main>
);
}

The Trail component renders a trail's name and status and allows the user to execute a to toggle the status of the trail between "OPEN" and "CLOSED":

const Trail = ({ id }) => {
const [updateTrail] = useMutation(UPDATE_TRAIL);
const { data } = useFragment({
fragment: TrailFragment,
from: {
__typename: "Trail",
id,
},
});
return (
<li key={id}>
{data.name} - {data.status}
<input
checked={data.status === "OPEN" ? true : false}
type="checkbox"
onChange={(e) => {
updateTrail({
variables: {
trailId: id,
status: e.target.checked ? "OPEN" : "CLOSED",
},
});
}}
/>
</li>
);
};

Notice that the Trail component isn't receiving the entire trail object via props, only the id which is used along with the fragment document to create a live binding for each trail item in the cache. This allows each Trail component to react to the cache updates for a single trail independently. Updates to a trail's status will not cause the parent App component to rerender since the @nonreactive directive is applied to the TrailFragment spread, a fragment that includes the status field.

Previous
Fragments
Next
Error handling
Edit on GitHubEditForumsDiscord

© 2024 Apollo Graph Inc.

Privacy Policy

Company