React-query and endpoint

Hi,

I’m using react-query’s useQuery to fetch some content (eventually to create a paginated news feed).

This works with an example endpoint like ‘https://countries.trevorblades.com/

But I just can’t work out how to combine the datocms endpoint and token so that I can query it here. I have it working elsewhere in the site using

import { GraphQLClient } from 'graphql-request'

export function request({ query, variables, preview }) {
    const endpoint = preview
        ? process.env.NEXT_DATOCMS_DRAFT_URL
        : process.env.NEXT_DATOCMS_LIVE_URL;

    const client = new GraphQLClient(endpoint, {
        headers: {
            authorization: `Bearer ${process.env.NEXT_DATOCMS_API_TOKEN}`
        }
    });
    return client.request(query, variables);
}

Please help point me in the right direction!

hi @steven I was able to use graphql-request with DatoCMS like so in node:

const GraphQLClient = require('graphql-request').GraphQLClient;
const gql = require('graphql-request').gql;

async function main() {
 const endpoint = 'https://graphql.datocms.com/'

 const graphQLClient = new GraphQLClient(endpoint, {
   headers: {
     authorization: 'Bearer YOUR_TOKEN',
   },
 })

 const query = gql`
   query MyQuery {
     allDogs {
       name
     }
   }
 `

 const data = await graphQLClient.request(query)
 console.log(JSON.stringify(data, undefined, 2))
}

main().catch((error) => console.error(error))

What error are you seeing in your project? Are your process.env variables set with the correct values?

Hi @fabrizio, thank you for replying!

I’m able to reach datoCMS in the site, but I’d like to build a News pagination page, or infinite scroll, using react-query’s useQuery.

This is my code (token removed). I feel like it isn’t hitting the endpoint:

import React from 'react'
import { useQuery } from 'react-query'
import gql from 'graphql-tag'
import { GraphQLClient, request } from 'graphql-request'

export const useGQLQuery = (key, query, variables, config = {}) => {
  const endpoint = `https://graphql.datocms.com/`

  const client = new GraphQLClient(endpoint, {
    headers: {
      authorization: `Bearer MY_TOKEN_HERE`
    }
  });
  // use await to wait until promise has been fulfilled
  const fethData = async () => await request(endpoint, client, query, variables)
  return useQuery(key, fethData, config); // useQuery from react-query
};

const GET_ALL_NEWS_CONTENT = gql`
    query {
      allNews {
        slug
        id
        title
      }
    }
`;

const AllNews = () => {
  // Fetch data from custom hook that uses React-Query
  const { data, isLoading, error } = useGQLQuery('allNews', GET_ALL_NEWS_CONTENT)
  console.log(data)

  if (isLoading) return <div>Loading…</div>
  if (error) return <div>Something went wrong…</div>

  return (
    <>
      <div className="generic-page">

        <h2>All News</h2>

        <div>
          {data.allNews.map(news => (
            <div key={news.title}>{news.title}</div>
          ))}
        </div>
      </div>
    </>
  )
};

export default AllNews;

I’ll look into that!

Alright @steven, there were a couple of errors in the setup, here’s a working example!

1 Like

Thank you @s.verna!! :slight_smile:

I’ve now implemented this and added useState to update the skip variable in my graphQL query along with some buttons.

However, one strange thing! … clicking the buttons does not update the news results unless you move away from the browser window and then go back again, then the content updates. Have I done something wrong here…

import React, { useState } from 'react'
import { useQuery } from 'react-query'
import gql from 'graphql-tag'
import { GraphQLClient } from 'graphql-request'

export const useGQLQuery = (key, query, variables) => {
  const endpoint = `https://graphql.datocms.com/`

  const client = new GraphQLClient(endpoint, {
    headers: {
      authorization: `Bearer MY_TOKEN_HERE`,
    }
  });

  return useQuery(key, () => client.request(query, variables));  // useQuery from react-query
};


const GET_ALL_NEWS_CONTENT = gql`
    query GetAllNewsContent ($first: IntType = 10, $skip: IntType = 0) {
      allNews(first: $first, skip: $skip, orderBy: _createdAt_DESC) {
        id
        title
        slug
      }
    }
`;

export default function AllNews() {
  const first = 5
  let [skip, skipNews] = useState(0)
  // Fetch data from custom hook that uses React-Query
  const { data, isLoading, error } = useGQLQuery(
    'allNews',
    GET_ALL_NEWS_CONTENT,
    { skip, first }
  );

  // console.log(data)

  if (isLoading) return <div>Loading…</div>
  if (error) return <div>Something went wrong…</div>

  return (
    <>
      <div className="generic-page">
        <button onClick={() => skipNews(0)}>page 1</button>
        <button onClick={() => skipNews(5)}>page 2</button>
        <button onClick={() => skipNews(10)}>page 3</button>
        <button onClick={() => skipNews(15)}>page 4</button>

        <h2>All News</h2>
        <div>
          {data.allNews.map(news => (
            <div key={news.title}>{news.title}</div>
          ))}
        </div>
      </div>
    </>
  )
};

@steven I’m not particularly familiar with react-query, but everything tells me this is not related to DatoCMS :smiley: I’d suggest asking directly to the react-query community, you’ll have better chances to get expenceried help in this regard!

@s.verna Ok will do, thank you again for helping with my code!

…just got back answer: I had to make skip part of the queryKey:

  const { data, isLoading, error } = useGQLQuery(
    ['allNews', skip],
    GET_ALL_NEWS_CONTENT,
    { skip, first }
  );

Just one more questions datoCMS related this time! :slight_smile: I’m currently adding my token directly into this component. I can’t seem to reference it using:

authorization: Bearer ${process.env.NEXT_DATOCMS_API_TOKEN}

…how should I hide my token?

hey @steven I’m sorry but the secret management is again something that is managed by your project, it’s difficult for us to help you there unless we have access to your repo :frowning:

I hope you understand. If you cannot figure that out yourself feel free to DM me so that you can maybe add me to your repo and I can help you out, OK?

1 Like

Thanks @mat_jack1! How do I DM you? (sorry new here!)

I have a file site up and working: lib/datocms.js

import { GraphQLClient } from 'graphql-request'

export function request({ query, variables, preview }) {
    const endpoint = preview
        ? process.env.NEXT_DATOCMS_DRAFT_URL
        : process.env.NEXT_DATOCMS_LIVE_URL;

    const client = new GraphQLClient(endpoint, {
        headers: {
            authorization: `Bearer ${process.env.NEXT_DATOCMS_API_TOKEN}`
        }
    });
    return client.request(query, variables);
}

Hi, how do I access process.env.NEXT_DATOCMS_API_TOKEN from a component? I need to update this code in my AllNews.js file:

export const useGQLQuery = (key, query, variables) => {
  const endpoint = `https://graphql.datocms.com/`

  const client = new GraphQLClient(endpoint, {
    headers: {
      authorization: `Bearer MY_TOKEN_SHOWN_HERE`,
    }
  });

  return useQuery(
    key, () => client.request(query, variables),
    { keepPreviousData: true }
  );  // useQuery from react-query
};

Thanks! :slight_smile:

oh I see, I think you need to see this page here: https://nextjs.org/docs/basic-features/environment-variables#exposing-environment-variables-to-the-browser ?

Thank you!

That’s now working on my localhost and deployment :slight_smile:

Created a new environment in Vercel containing my token and NEXT_PUBLIC_API_TOKEN.

Then vercel env pull to update my files.

And updated this line: authorization: Bearer ${process.env.NEXT_PUBLIC_API_TOKEN},`

1 Like