Fetching data in a sequential manner within a Server Component to manipulate a consistent data set in Next.js

Recently diving into the world of next.js (utilizing v13 with App Router), I find myself in search of guidance regarding a particular challenge I've been wrestling with.

My objective is to dynamically render data on a page and incrementally update it as "improved" data becomes available (e.g., more recent data, data from additional sources, etc.). Typically, there should be 2-3 updates until the data loading process is complete (similar to how options on a hotel booking website progressively update before the loading indicator disappears). I aim to handle this process primarily server-side.

Whenever an update is required, the API response from my Django backend contains a "next" entry along with a URL, for example:

{ "meta": {..., "next": "https://api.example.com/path/to/next/request"}, 
  "data": ... }

The official next.js documentation provides clarity on sequential data fetching, but does not elaborate on how to update the same dataset; instead, it focuses on progressively displaying different sets of data.

After experimenting with various approaches, I devised a solution that involves utilizing a recursive component, where a <Suspense> boundary is populated with the current data acting as the fallback.

import { Suspense } from 'react';

export default async function Stream() {
  return (
      <div className='m-auto h-screen w-1/2 p-3'>
        <h1>Welcome to the Stream page!</h1>
        <Results url={'http://127.0.0.1:3000/api/dummyData'} />
      </div>
  );
}

async function Results({ url }: { url?: string }) {
  const content = await fetch(url, {
    cache: 'no-store',
  }).then((res) => res.json());
  
  // if "next" URL is present in the response, include it in the recursive function
  if (content.next) {
    return (
      <Suspense fallback={<ResultsDisplayer content={content} />}>
        <Results url={content.next} />
      </Suspense>
    );
  } else {
    return <ResultsDisplayer content={content} />;
  }
}

async function ResultsDisplayer({ content }) {
  const isLoading = Boolean(content.next);
  return (
    <>
      <p>Loading: {isLoading ? 'YES' : 'NOPE'}</p>
      <br />
      <p>Data:</p>
      <pre>{JSON.stringify(content)}</pre>;
    </>
  );
}

Demonstration of the recursive solution (GIF)

This approach appears functional, yet I am interested in exploring a possibly more conventional or straightforward method to accomplish server-side data modifications prompted by linked hyperlinks. Thus far, I have not come across any comprehensive examples or documentation addressing this specific scenario.

Throughout my research, I explored alternative avenues, none of which seemed entirely suitable:

  • Client-side updates (e.g., employing useSWR and useEffect), though I aimed to steer clear of client-side fetching
  • Websocket implementation, deemed potentially excessive and seemingly only applicable for client-side consumption
  • ReadableStream utilization, as outlined in the next.js documentation on route handlers, unfortunately unsuccessful in my attempts (and did not appear conducive to server-side use)
  • Server Actions, leveraging the revalidateTag, still in an experimental phase and presented challenges conveying refresh signals to clients

Have any of you encountered a similar issue? If so, how did you navigate through it? Are there facets of next.js that may have eluded me or been misinterpreted?

Appreciate your insights! :)

Answer №1

This question brings up an intriguing idea. It seems like you're aiming to streamline the process by making just one HTTP request, send response data gradually, and have the client update as the data streams in.

Using streams both on the server and client side is essential for this task.

To start, you'll want to reply with a ReadableStream. The code for this may be complex, but you can check out this GitHub discussion on sending files with Route Handlers for different syntax examples.

On the client side, you can fetch this endpoint and consume the stream using a similar API. The fetch Response body will contain a ReadableStream with your data.

You can utilize stream event handlers to update a state variable that will trigger a rerender of your component. While there are potential solutions like <Supspense /> or utilizing incoming use hooks, sticking to event handlers instead of promises on the client side would suffice.

One thing to consider is how to separate each data chunk into standalone pieces (strings that can be JSON.stringify). One approach could be sending the chunk size along with the chunk itself (e.g., sending the size, then string, repeating until -1 is sent to close the stream).


In practice, one challenge you might face is that within Route Handlers, you must provide a Response object before Next.js initiates the HTTP response process. In contrast, in an API Route/Express endpoint, you can call res.send at any point and supply the stream.

The issue arises in understanding the stream's lifecycle: can you continue feeding the stream even after returning from the Route Handler function? Though it should theoretically work, testing it out is advisable.

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

When I engage with the input field, it ceases to be in focus

Here is the code I've been working on: https://github.com/Michael-Liendo/url-shortener/blob/main/src/pages/index.js If you want to see the issue for yourself, check it out at: ...

How can I retrieve a text file using an API in a Next.js application?

Is there a way to download a text file using an API in Next.js? The console.log(ninjas) function is already displaying the correct information. I have tested the API with Postman and it works perfectly. When I use GET in Postman, the same information is ...

Utilize the data storage API within Next.js or directly in the user's

Struggling to store this ini file on either the server or client, any help would be greatly appreciated. Additionally, I would like to display the ini info in the browser so that clients can easily copy and paste the information. However, I seem to be fac ...

Effective Ways to Redirect During or After Executing the onClick Function of Button

I am currently working on implementing a feature for my Next.js website. The functionality involves allowing users to create a new group by clicking a button, and then being redirected to an "Invite members" page with the auto-generated group_id included i ...

The Parallax effect reference hook does not seem to be functioning properly with components in NextJs

I'm attempting to implement the useParallax hook on an element within my JavaScript file. My setup involves NextJs, ReactJs, and styled components. Here is how I integrated the hook: Mainland.js import React, { useEffect, useRef } from 'react&ap ...

Image broken despite accurate file path in next.js and tailwind

https://i.stack.imgur.com/2ZqPa.png In my components folder, specifically in navbar.js, I have a path to the image folder <img className="block lg:hidden h-8 w-auto" src='../images/logo_injoy.png' alt="Logo" /> U ...

Warning in Next.js: When utilizing conditional rendering, the server HTML is expected to have a corresponding <div> inside another <div>

Although similar questions have been asked on various platforms like Google, none seem to provide answers that align with my specific situation. Essentially, my goal is to have a different search bar displayed in the header based on the page I am currentl ...

Images on NextJS are failing to resize properly in Next 13

I have been facing challenges with optimizing image sizes for different screen resolutions using the NextJS Image component. Currently, all images seem to be loading at their largest size on various screens. Below is a screenshot showing the resolution t ...

What is the best way to reset form after submission in Next.js?

I have a contact form and I want all the form values to be cleared after submitting the form. I've tried the following code, but the values of the form remain unchanged after submission. What could be causing this issue and how can it be resolved? ...

What is the rationale behind transmitting JSON data within HTML in Next.js's static site generation (

When a webpage is loading, the entire HTML document is sent, whereas in client-side routing, only the JSON file and JS chunk are sent. But why does the HTML file filled with data need to contain JSON data too? Is it really necessary since we already have ...

A problem arose with Vitest when attempting to call the tRPC createCaller function due to the presence of incorrect JS syntax within the content. To resolve this issue, it is recommended to include

Currently, I am in the process of writing unit tests with Vitest and utilizing the tRPC createCaller to simulate the trpc context. However, I am encountering a failure during testing which presents the following error message: Error: Failed to parse sourc ...

When implementing variables from input boxes, my SQL query fails to populate any data in the database table

I have been using phpMyAdmin to store test data. As I try to insert data from a form, I encounter an issue where no data gets inserted when using variables in the SQL query. Being new to coding, I am struggling to find a solution to this problem. Additiona ...

What is the best way to convert my Chatbot component into a <script> tag for seamless integration into any website using React.js?

I have successfully integrated a Chatbot component into my Next.js application. https://i.stack.imgur.com/BxgWV.png Now, I want to make this component available for anyone to use on their own website by simply adding a tag. My initial approach was to cre ...