Querying from the client
Depending on whether you are querying data from React Server Components, a client component in the app router, or a client component in the pages router, you will need to use a different set of data fetching helpers.
Fragments
One of the pillars of fuse is Fragment co-location, we strongly believe that this patterns helps
us get a better overview of our data-requirements and makes it easier to reason about the data
a component will receive.
When creating components it's useful to co-locate your data-requirements with your component,
this way when you need more data for your component you know exactly where to add it and
you don't have to go up your component-tree to find the query responsible for adding the data.
import { FragmentType, graphql, useFragment } from '@/fuse'
const UserFields = graphql(`
fragment Avatar_UserFields on User {
firstName
avatarUrl
}
`)
export const Avatar = (props: {
user: FragmentType<typeof UserFields>
}) => {
const user = useFragment(UserFields, props.user)
return (
<div>
{(user.avatarUrl && user.firstName) && <img src={user.avatarUrl} alt={user.firstName} />}
<span>Welcome, {user.firstName}</span>
</div>
)
}The above defined fragment is now globally available and we can add it to our query:
import { graphql } from '@/fuse'
const UserQuery = graphql(`
query User ($id: ID!) {
user(id: $id) {
...Avatar_UserFields
}
}
`)From now on out, every time we need a new field in the Avatar component we can just add it there
and trust that the query is updated automatically and our data is passed into the component by menans of
<Avatar user={result.data.user} />.
All Fragments you define in a component will be globally available, this means that if your client components define their data requirements you can spread your fragments in your top-level server-component and pass the data down.
Type-conditions
Something you might notice when we define a fragment is that we add this on X keyword after the name,
this is called a type-condition and is used to tell the GraphQL
that we only want those fields when the type is either X or a type that inherits from X (like with interfaces).
Generated files
When you run next dev for the first time you'll see the fuse/ folder populate
with a bunch of files. These don't need to be touched and are mostly there to
help with typing your results, variables and facilitating the client-methods.
Let's go over each file:
fuse/server.ts: This is the main entry-point for the/appdirectory when you are working with server-components and server-actions. It exports anexecutefunction which takes aDocumentandvariablesand will perform that on the datalayer.fuse/client.ts: This is the main entry-point for the/appdirectory when you are in'use client'mode. It exports theuseQuery/... hooks which you can use in your components to talk to your datalayer.fuse/pages.ts: This is the main entry-point for the/pagesdirectory. It exports thewithUrqlClinetandinitUrqlClientto work withgetServerSideProps, ... As well as React hooks which you can use in your components.fuse/fragment-masking.ts: TheuseFragmentandFragmentTypehelpers are exported from here, these helpers basically ensure that the props you pass in will be reduced to the selection of fields of your fragment.fuse/gql.ts: Thegraphql()function is exported from here, this helper ensures that both theResultandVariablesare typed correctly for a givenDocument.fuse/graphql.ts: This file contains a translation of your GraphQL schema to TypeScript types. It also contains theDocumenttype which is a helper type to type your GraphQL documents.