Using map on data from graphql

Using map on data from graphql


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"
        }
      }
    ]
  }
}

Share
Improve this question

1 Answer
1

Reset to default


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.

Share
Improve this answer

3

  • these are the type generated with codegen, I haven't created them

    – cdmt

    2 hours ago

  • I have updated the question with the console log you suggested

    – cdmt

    2 hours ago

  • 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

    1 hour ago



Leave a Reply

Your email address will not be published. Required fields are marked *