0

I have a nextjs app using typescript and a Strapi backend with graphql

I'm trying to simple get the graphql from strapi and display it in the react app.

I'm trying to display a list of font names.

In react I have this query, this works in the playground

import { gql } from "@/node_modules/@apollo/client/core/index";

export const FONT_DATA = gql`
    query font_data{
        fonts{
            data{
                attributes{
                    font_name
                }
        }
    }
}
`

I'm generating types using codegen.

export type Font = {
  __typename?: 'Font';
  createdAt?: Maybe<Scalars['DateTime']['output']>;
  font_name?: Maybe<Scalars['String']['output']>;
  publishedAt?: Maybe<Scalars['DateTime']['output']>;
  updatedAt?: Maybe<Scalars['DateTime']['output']>;
};

export type FontEntity = {
  __typename?: 'FontEntity';
  attributes?: Maybe<Font>;
  id?: Maybe<Scalars['ID']['output']>;
};

export type FontEntityResponse = {
  __typename?: 'FontEntityResponse';
  data?: Maybe<FontEntity>;
};

export type FontEntityResponseCollection = {
  __typename?: 'FontEntityResponseCollection';
  data: Array<FontEntity>;
  meta: ResponseCollectionMeta;
};

export type FontFiltersInput = {
  and?: InputMaybe<Array<InputMaybe<FontFiltersInput>>>;
  createdAt?: InputMaybe<DateTimeFilterInput>;
  font_name?: InputMaybe<StringFilterInput>;
  id?: InputMaybe<IdFilterInput>;
  not?: InputMaybe<FontFiltersInput>;
  or?: InputMaybe<Array<InputMaybe<FontFiltersInput>>>;
  publishedAt?: InputMaybe<DateTimeFilterInput>;
  updatedAt?: InputMaybe<DateTimeFilterInput>;
};

export type FontInput = {
  font_name?: InputMaybe<Scalars['String']['input']>;
  publishedAt?: InputMaybe<Scalars['DateTime']['input']>;
};  

In react I have a simple page where I am calling the query and trying to display the font names

'use client'
import { getDataFromTree } from '@apollo/client/react/ssr'
import withApollo from '../lib/withApollo'
import { FontEntity,  FontEntityResponse,  FontEntityResponseCollection} from '@/generated'
import { useQuery } from '@apollo/client'
import { FONT_DATA } from '@/graphql/queries'

const Home = () => {
  // const data: FontEntityResponse  = useThemeContext()?.data;

  const {data, loading} = useQuery<FontEntityResponse, FontEntity>(FONT_DATA)

  if(loading || !data) return <div>Loading</div>

  console.log(Array.isArray(data))

  return (
    <div>
      <ul>
        {data?.data?.attributes?.map((font:FontEntity) => (
          <li key={font.id}>{font?.font_name}</li>
        ))}
      </ul>
    </div>
  );
}

export default withApollo(Home, { getDataFromTree });

The map errors with Property 'map' does not exist on type 'Font' which is because its not an array.

The console.log also says its not an array.

The graphql returns an object but how do I use that with the map, or am I using the wrong type.

Update

if I do console.log(JSON.stringify(data, null, 2))

I get

{
  "fonts": {
    "__typename": "FontEntityResponseCollection",
    "data": [
      {
        "__typename": "FontEntity",
        "attributes": {
          "__typename": "Font",
          "font_name": "Black"
        }
      },
      {
        "__typename": "FontEntity",
        "attributes": {
          "__typename": "Font",
          "font_name": "Jasper"
        }
      },
      {
        "__typename": "FontEntity",
        "attributes": {
          "__typename": "Font",
          "font_name": "Varly"
        }
      },
      {
        "__typename": "FontEntity",
        "attributes": {
          "__typename": "Font",
          "font_name": "Brother"
        }
      }
    ]
  }
}
cdmt
  • 685
  • 4
  • 12
  • 23

1 Answers1

0

I'm not sure how it works with strapi, but usually graphql response looks like this:

data.nameOfYourResolver.arrayObjectOrOtherTypeOfData

Your types are all wrong. In your case, it should look something like this:

export type FontEntityResponse = {
  fonts: Maybe<FontEntityData>; //object
};

export type FontEntityData = {
  data: Maybe<FontEntity[]> //Array
};

export type FontEntity = {
  attributes: Maybe<Font>; //Object

export type Font = {
  fontName: Maybe<string>; //string



data.fonts.data(attribute => {
   console.log(attribute.font_name)
//...
})

Again, I don't know what type of data is it exactly, but your property names are wrongly named

All you need to do is check for the types of these properties

fonts{
       data{
            attributes{
               font_name }}}

You can console.log(JSON.stringify(data, null, 2)) to see all the data inside

Also, I think that in const {data, loading} = useQuery<FontEntityResponse, FontEntity>(FONT_DATA)

FontEntity should supposed to be used for variable types that are used when fetching this resolver.

SlothOverlord
  • 1,655
  • 1
  • 6
  • 16
  • these are the type generated with codegen, I haven't created them – cdmt Aug 31 '23 at 09:12
  • I have updated the question with the console log you suggested – cdmt Aug 31 '23 at 09:16
  • Well it looks like it generated the wrong types. I updated my answer. Maybe they are outdated or something, but based on the console.log you provided, it is ```data.fonts.data.map``` – SlothOverlord Aug 31 '23 at 09:24
  • These types are from the Graphql Code Generator - https://the-guild.dev/graphql/codegen – cdmt Aug 31 '23 at 17:51