Client components
When you are leveraging the use client
directive in a /app
component we have opted out
of using server-components. This means we are going back to the traditional way of
distributing our client over React.context
.
It is advisable to create a Provider
component with 'use client'
that you use in your
root-layout component so we are enabled to query data in any client page.
'use client'
import {
Provider,
createClient,
} from '@/fuse/client'
import React from 'react'
export const DatalayerProvider = (props: any) => {
const [client, ssr] = React.useMemo(() => {
const { client, ssr } = createClient({
url: 'http://localhost:3000/api/fuse',
// This is used during SSR to know when the data finishes loading
suspense: true,
})
return [client, ssr]
}, [])
return (
<Provider client={client} ssr={ssr}>
<React.Suspense>
{props.children}
</React.Suspense>
</Provider>
)
}
Let's add this to app/layout.tsx
so we are enabled to query data in any subsequent page.
Querying data cna be done by using the useQuery
hook from your generated fuse folder.
import { useQuery } from '@/fuse/client'
import { graphql } from '@/fuse'
const UserQuery = graphql(`
query User ($id: ID!) {
user(id: $id) {
...Avatar_UserFields
}
}
`)
function User() {
const [result] = useQuery({
query: UserQuery,
variables: { id: '1' },
})
}
When you need to reach into your mutatation entry points we supply useMutation
as well.
import { graphql } from '@/fuse'
import { useMutation } from '@/fuse/client'
const UpdateUser = graphql(`
mutation UpdateUser ($id: ID!, firstName: $String!) {
user(id: $id, firstName: $firstName) {
...Avatar_UserFields
}
}
`)
const UpdateUser = () => {
const [result, update] = useMutation(UpdateUser)
return (
<button onClick={() => update({ id: '1', firstName: 'John' })}>
Update user
</button>
)
}
When you mutate data that is queried from a server-component you will need to call
router.refresh()
to re-render your server-component. The router is a hook exported fromnext/navigation
nameduseRouter
.
For data queried from client-components the client cache will recognise that data got
altered and performa refetch. The cache matches this by means of the __typename
property
that is available on the data.
Heads up, when you query a list of items that is empty we won't be able to infer the
__typename
and you will need to supply it yourself.
import { useMemo } from 'react'
import { graphql } from '@/fuse'
import { useQuery } from '@/fuse/client'
const UserQuery = graphql(`
query User ($id: ID!) {
user(id: $id) {
...Avatar_UserFields
}
}
`)
const User = () => {
const [result] = useQuery({
query: UserQuery,
variables: { id: '1' },
context: useMemo(() => ({ additionalTypenames: ['User'] }), []),
})
}
Similar to the above we can perform mutations on the client as well by means of the useMutation
hook,
this hook is lazy, when we invoke it we'll get a function that we can invoke to execute it.
import { graphql } from '@/fuse'
import { useMutation } from '@/fuse/client'
import { redirect } from 'next/navigation'
const SayHello = graphql(`
mutation Hello($name: String!) {
sayHello(name: $name)
}
`)
export async function Greet(args: { name: string }) {
const [result, execute] = useMutation(SayHello)
return <button onClick={() => execute({ name })}>Greet</button>
}