When incorporating React-query with Next.js and utilizing hydration configuration for server-side rendering, cached results are not utilized, leading to the need to perform another fetch request

While working on my nextjs app, I decided to implement react-query with SSR/SSG and went through several tutorials. I opted for the hydration configuration over the initialData approach as it seemed more efficient.

Following the instructions in the react-query guide at , all you have to do is wrap your app in QueryClientProvider and Hydrate components, passing a prop to each one.

    const App = ({ Component, pageProps }: AppProps) => {
      const [queryClient] = useState(
        () => new QueryClient({ defaultOptions: { queries: { staleTime: 30 * 1000 } } })
      )

      return (
        <QueryClientProvider client={queryClient}>
          <Hydrate state={pageProps.dehydratedState}>
            <ReactQueryDevtools initialIsOpen={false} />
            <ThemeProvider theme={theme}>
              <CssBaseline />
              <Component {...pageProps} />
            </ThemeProvider>
          </Hydrate>
        </QueryClientProvider>
      )
    }

    export default App

To fetch data using react-query within

getServerSideProps/getStaticProps
, simply create a new instance of queryClient, call prefetchQuery, and set a prop with dehydrate(queryClient).

    export async function getStaticProps() {
      const queryClient = new QueryClient()
      await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)

      return {
        props: {
          dehydratedState: dehydrate(queryClient),
        },
      }
    }

    const Home: NextPage = () => {
      const { data, isLoading } = useQuery<Todo[]>('todos', fetchTodos)
      console.log(isLoading)

      if (isLoading) return <h1>Loading...</h1>

I've set up a small API that returns the same data as https://jsonplaceholder.typicode.com/todos, but with a setTimeout of 3 seconds. However, every time I reload or navigate between pages using next/link, there is a 3-second delay in loading the page, indicating that the react-query cache is not being utilized.

I tried moving the queryClient instance outside of getServerSideProps and also adding staleTime to all queries as per my configuration above.

The only solution I found was:

    export const queryClient = new QueryClient()

    export async function getStaticProps() {
      if (!queryClient.getQueryData('todos')) {
        await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)
      }

      return {
        props: {
          dehydratedState: dehydrate(queryClient),
        },
      }
    }

However, I couldn't find much discussion about this issue and it feels like I might be approaching it incorrectly.

This screenshot from my network tab shows the activity when navigating between pages before 30 seconds elapse based on my staleTime configuration and having the queryClient instance outside of gssp: enter image description here

Answer №1

When you create the queryClient outside of the getStaticProps function, you are effectively sharing it across multiple requests and users. This may or may not be the desired behavior for your application. The lifespan of a QueryClient created outside of getStaticProps is uncertain.

Instead of using an if statement to check for data before prefetching, consider passing a staleTime parameter to the prefetchQuery method. This will retrieve cached data if available, otherwise it will fetch new data:

await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos, { staleTime: 1000 * 60 * 10 })

Another approach is to create a new cache within the getStaticProps / getServerSideProps functions and populate it with data from an external source, such as a redis cache. You can find more information on this topic in the following discussion: https://github.com/tannerlinsley/react-query/discussions/3563

Answer №2

In my search for a solution to a particular issue, I came across this interesting workaround that was discussed in a GitHub thread. The workaround was also highlighted in a blog post.

export const hasNavigationCSR = (next) => async (ctx) => {
  if (ctx.req.url?.startsWith('/_next')) {
    return {
      props: {},
    };
  }
  return next?.(ctx);
};

Subsequently,

export const getServerSideProps = hasNavigationCSR(async (ctx) => {
  const queryClient = new QueryClient()
  if (!queryClient.getQueryData('todos')) {
    await queryClient.prefetchQuery<Todo[]>('todos', fetchTodos)
  }

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a registration and authentication system using firebase

When using Google authentication with Firebase, is the Signup and Login logic the same? I am creating a page for user authentication but I'm unsure if I should have separate pages for signing up and logging in. This confusion arises from the fact that ...

What is the best way to specifically target and style a component with CSS in a React application?

I'm facing a small issue with the React modals from Bootstrap in my application. In index.html, I include the following: <link rel="stylesheet" href="/assets/css/bootstrap.min.css"> <link rel="stylesheet" href=& ...

What is the best way to eliminate the label from a MUI 5 TextField without the notched style?

I am currently in the process of updating our app's DatePicker component to use the new @mui DatePicker. However, I am facing difficulty in rendering the TextField without the floating label and notched input style. Below is my most recent attempt: &l ...

A guide to connecting keyboard events to div elements within a React application

Currently working on a basic react project to gain some practical experience with the library. I aim to develop a simple user interface with blank spaces to be filled in by typing via keyboard input. Here's a glimpse of my progress so far: function ...

What steps are involved in importing remark-gfm into next.config.js?

I am interested in incorporating MDX into next.js with the remark-gfm plugin. After discovering the Next.js Docs on MDX, I decided to follow their guidelines and added an import statement. // next.config.js import remarkGfm from 'remark-gfm;' co ...

Using turbopack with Next.js version 13 results in a "TypeError: Class extends value #" error, whereas no error occurs when using webpack

Recently, my Next.js 13 app running on Turbopack encountered a sudden issue after a few commits. The error message displayed is quite vague - TypeError: Class extends value # in the browser, Uncaught ReferenceError: $RefreshSig$ is not defined in the conso ...

Mastering React-Table: Learn how to optimize your Material-UI table by implementing useResizeColumns alongside a sticky header feature

Is there a way to implement column resizing in a Material-UI table using the latest version (7.5.x) of React-Table without compromising the 'Sticky Header' functionality? The dilemma arises when attempting to enable column resizing with either & ...

Issue with Material UI causing slow compilation in Next.js version 13

When trying to integrate Material UI with Next.js 13 (App router), I noticed that the compilation time during development is significantly slow. Is there a way to optimize this and decrease the compiling time? Experiencing slow compilation when using Mate ...

The Array Find() method keeps returning 'undefined' when trying to search for data based on URL parameters

Is there a way to display data from an array based on a specific condition? I have been attempting to do this by checking if the requested id matches any of the ids in the data array. Unfortunately, whenever I run the following code snippet, I always end u ...

Create a three-dimensional tree array in Typescript/Javascript by transforming a flat array

Received data is structured as follows: const worldMap = [ { "name": "Germany", "parentId": null, "type": "Country", "value": "country:unique:key:1234", "id&qu ...

"Experiencing a problem with Next.js 13 where the User Context is not functioning properly outside of _app

When using Next.js 13 and the user context, I've noticed that it doesn't function properly outside of _app.tsx. Any idea why? src>context>UserPositionContext.tsx import { createContext, useContext, useState } from "react"; const ...

React button remains inactive

After only four months of learning and developing in react, I decided to create a simple portfolio for myself. However, I encountered an issue with a toggler and a button that I included in the navbar - they simply won't respond when clicked no matter ...

Can the Auleria framework integrate with React Material UI components?

I am looking to use the auleria framework for controlling and modeling (getting data from the backend, routing, and logic) and React for data binding in my project. I came across an example of using auleria-react at this link. I also want to incorporate ...

Passing parameters to a custom toolbar in Material-UI Data-Grid. How can it be done?

I have been working on creating a custom toolbar for a datagrid using Material-UI. I referenced the documentation at this link and started from this example: here My goal is to show or hide the toolbar with a transition. Since we can't pass custom pr ...

I can't seem to find a dispatch function in Next.js with thunk to load user data post login

Whenever I attempt to call getUserProfile(), I encounter a TypeError stating that dispatch is not a function Runtime Error Unhandled Error: Actions must be plain objects. Make use of custom middleware for async actions. export const fetchUserProfile = (us ...

The state variable is consistently undefined when accessed in a callback function

Having trouble understanding how state works when returning a callback function. The useWeb3React is active (logs in the useEffect), but the account in the getAccountMatch function is always undefined. I've tried various solutions like adding a callba ...

What steps can I take to decrease the padding of this footer?

Is there a way to reduce the height of the footer so it doesn't dominate the screen on both large and small devices? import { Container, Box, Grid } from "@material-ui/core"; const Footer = (props) => { return ( <footer> ...

Tips for preventing a React component from scrolling beyond the top of the page

I am looking to achieve a specific behavior with one of my react components when a user scrolls down a page. I want the component to reach the top of the page and stay there without moving any further up. Here is an Imgur link to the 'intranet' ...

I'm keen on creating a marquee animation using Tailwind and Next.js

I'm working on creating a marquee animation using Tailwind CSS and Next.js, and I've made some progress. However, the issue I'm facing is that the items are not displaying one after the other smoothly; there seems to be a delay when the seco ...

Customize language settings on a multilingual site using next.js

Just recently, I embarked on my Next.js journey and dove into creating my inaugural website, aiming for a multilingual touch. To guide me along the way, I diligently followed the official documentation at https://nextjs.org/docs/app/building-your-applicat ...