Using GROQ queries in Next.js components and the limitations of fetching data on the client-side.

11 replies
Last updated: Dec 18, 2021
help: I use the GROQ query in the next js components, not pages. it's not fetching data. showing empty array. But on the other hand, if add this query on the page its works fine. So the question is how I use this query in the header, footer, others.              So please someone help me? How I write query I next component. So my code is..  

import React from 'react';
import groq from 'groq';
import sanity from '../../utils/sanity';

import { Heading } from '../elements';

const ReviewBlock = ({ title, products = [] }) => {
  console.log(products, 'products');
  return (
    <section className="section is-medium">
      <div className="container">
        {title && (
          <Heading centered className="has-text-black mb-6">
            {title}
          </Heading>
        )}
      </div>
    </Section>
  );
};
export async function getStaticProps() {
  return {
    props: {
      products: await sanity.fetch(groq`
          *[_type == "product" && isFeatured && !(_id in path('drafts.**'))] {"id": _id, ...}|order(publishedAt desc)
        `),
    },
  };
}
export default ReviewBlock;
AI Update

I can see the issue! You're trying to use getStaticProps inside a component file, but getStaticProps only works in page files in Next.js (files inside the pages/ directory). That's why it works on pages but returns an empty array in your component.

Here are your solutions depending on your Next.js version:

For Next.js App Router (13+)

Convert your component to a Server Component and fetch data directly inside it:

import React from 'react';
import groq from 'groq';
import { createClient } from 'next-sanity';
import { Heading } from '../elements';

// Create your Sanity client
const client = createClient({
  projectId: 'your-project-id',
  dataset: 'production',
  apiVersion: '2024-01-01',
  useCdn: true,
});

const ReviewBlock = async ({ title }) => {
  // Fetch directly in the component
  const products = await client.fetch(groq`
    *[_type == "product" && isFeatured && !(_id in path('drafts.**'))] 
    {"id": _id, ...} | order(publishedAt desc)
  `);

  console.log(products, 'products');
  
  return (
    <section className="section is-medium">
      <div className="container">
        {title && (
          <Heading centered className="has-text-black mb-6">
            {title}
          </Heading>
        )}
      </div>
    </section>
  );
};

export default ReviewBlock;

This works because Server Components in the App Router can be async and fetch data directly.

For Next.js Pages Router (12 and below)

You have two options:

Option 1: Fetch in the page and pass as props

// pages/your-page.js
export async function getStaticProps() {
  const products = await sanity.fetch(groq`
    *[_type == "product" && isFeatured && !(_id in path('drafts.**'))] 
    {"id": _id, ...} | order(publishedAt desc)
  `);
  return {
    props: { products }
  };
}

export default function YourPage({ products }) {
  return <ReviewBlock title="Reviews" products={products} />;
}

// components/ReviewBlock.js
const ReviewBlock = ({ title, products = [] }) => {
  // Just use the products prop
  console.log(products, 'products');
  return (/* your JSX */);
};

Option 2: Fetch client-side with SWR or useEffect

import useSWR from 'swr';
import groq from 'groq';
import sanity from '../../utils/sanity';

const ReviewBlock = ({ title }) => {
  const { data: products = [] } = useSWR(
    groq`*[_type == "product" && isFeatured && !(_id in path('drafts.**'))] 
         {"id": _id, ...} | order(publishedAt desc)`,
    (query) => sanity.fetch(query)
  );

  console.log(products, 'products');
  return (/* your JSX */);
};

For shared components (Header/Footer)

For layout components that need data:

  • App Router: Create them as async Server Components (like the first example above)
  • Pages Router: Fetch data in your page's getStaticProps and pass it down, or use client-side fetching with SWR/React Query

The key takeaway: getStaticProps and getServerSideProps are page-level only in the Pages Router. For components, you either need to pass data down as props, use Server Components (App Router), or fetch client-side.

Check out the next-sanity package documentation for more patterns on integrating Sanity with Next.js!

I think getStaticProps etc only work on pages iirc.
You could maybe try using the
useEffect
hook to fetch the data in the component instead?
Just looking through the Nextjs documentation, my above message might not be correct, example https://nextjs.org/docs/basic-features/data-fetching#example
user B
you are correct, you can only use getStaticProps in a page not a component
You can’t fetch data at a component level. What you’ll need to do is either extract your global data at build time with something like next-plugin-preval or pass the it as props in your layout component.
user P
Ah ok, that was my first thought but started to second guess myself 😄
thanks,
user B
it's working now.
 const [review, setReview] = useState(null);

  useEffect(() => {
    sanity
      .fetch(
        groq`
        *[_type == "product" && !(_id in path('drafts.**'))] {"id": _id, ...}
        `,
      )
      .then((data) => setReview(data));
  }, []);
  console.log(review);
Bingo
user B
can you please explain to me? is it good or bad? Fetch data direct in components. Nextjs now allow this in their props( getstaticprops , getInitial , etc).. Give me a pro tip. if it wrong method then I remove it from my code and find the better one.
Non-page component cannot fetch their own data on the server side. So you need to fetch it in the page it is in and pass that data down as props. If the data is used widely throughout the site, I'd fetch it in
_app
and make it available through context.
The workaround you are using above is fetching data on the client side, at run-time. Now this is not entirely bad but might affect your SEO, as that component's rendered content won't be available when the bot is crawling your site. And server rendered markup (especially when used with static optimization) will most of the time result in faster first load.
user M
Thank you for giving me this information. Thanks
Not to mention each page load will result in an api request, counting towards the limits.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?