Next.js 14 useEffect firing twice upon page load

Having an issue with a client component in next js that is calling an API twice at page load using useEffect. Here's the code for the client component:

'use client';

import { useState, useEffect } from 'react';
import { useInView } from 'react-intersection-observer';

import { CaretSortIcon, CheckIcon } from '@radix-ui/react-icons';
import { cn } from '@/app/lib/utils';
import { Button } from '@/components/ui/button';
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/command';
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from '@/components/ui/popover';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useDebouncedCallback } from 'use-debounce';

let offset = 0;

export function ComboboxDemo({ services }: { services: string[] }) {
  const [open, setOpen] = useState(false);
  const [value, setValue] = useState('');

  const searchParams = useSearchParams();
  const initialQuery = searchParams.get('query_service') || '';
  const [inputValue, setInputValue] = useState(initialQuery);

  const { replace } = useRouter();
  const pathname = usePathname();

  const { ref, inView } = useInView();
  const [data, setData] = useState<string[]>([]);

  useEffect(() => {
    if (inView) {
      const fetchService = async () => {
        const response = await fetch(
          `/dashboard/inventory/api/services?offset=${offset}`,
        );
        const result = await response.json();
        return result;
      };
      fetchService().then((res) => {
        setData([...data, ...res]);
      });
    }
    console.log('i fire once');
  }, [inView, data]);

Here is the corresponding API endpoint:

import { db } from '@/drizzle/db';
import { evergreen } from '@/drizzle/schema';
import { ilike, sql } from 'drizzle-orm';
import { NextRequest, NextResponse } from 'next/server';

const limit = 100;

export async function GET(req: NextRequest) {
  const { searchParams } = new URL(req.url);
  const offset = searchParams.get('offset') || 0;

  const dataPromise = db
    .selectDistinct({
      it_service: evergreen.it_service,
    })
    .from(evergreen)
    .offset(sql.placeholder('offset'))
    .limit(limit)
    .prepare('distinct_it');

  const data = await dataPromise.execute({ offset: offset });
  console.log(data);

  const services = data.map((item) => item.it_service);

  return NextResponse.json(services, { status: 200 });
}

Note: Not running in Strict Mode and the API endpoint is a route handler, not a server action.

Answer №1

It appears that a dependency has been added to the useEffect hook which causes the callback to update. This will result in the effect running again.

useEffect(() => {
  if (inView) {
    const fetchService = async () => {
      const response = await fetch(
        `/dashboard/inventory/api/services?offset=${offset}`,
      );
      const result = await response.json();
      return result;
    };
    fetchService().then((res) => {
      setData([...data, ...res]); // <-- updates data state
    });
  }
  console.log('i fire once');
}, [inView, data]); // <-- data state is dependency

To avoid data being an external dependency, use a functional state update where an updater function is used to compute and return the next state value based on the current state value.

Example:

useEffect(() => {
  if (inView) {
    const fetchService = async () => {
      const response = await fetch(
        `/dashboard/inventory/api/services?offset=${offset}`,
      );
      const result = await response.json();
      setData(data => [...data, ...result]);
      // or setData(data => data.concat(...result));
    };

    fetchService();
  }
}, [inView]);

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

Having difficulty authenticating Slack requests

I'm currently working on a project to develop a Slack bot using the events API for an experiment at my job. I am facing challenges in verifying the request and can't seem to pinpoint where I'm making a mistake. The bot is being built using ...

Display all pages in the DataTables plugin while utilizing responsive tables and additional features

I am struggling to combine the responsive and fixed header attributes of my current function with the "Show All" list feature, similar to what is demonstrated in this example: https://datatables.net/examples/advanced_init/length_menu.html I need assistanc ...

"Find the URL for Next and Strapi mySQL connection at the root directory

This tutorial focuses on using a postgre database example. I set up strapi and next on my computer but I'm struggling to find the MySQL URL. Despite searching through documentation and other resources, I have not been able to locate it. I am using ...

Refresh a page automatically upon pressing the back button in Angular

I am currently working on an Angular 8 application with over 100 pages (components) that is specifically designed for the Chrome browser. However, I have encountered an issue where the CSS randomly gets distorted when I click the browser's back button ...

What is the process for obtaining a fresh token from Cognito using the frontend?

Currently, I am working with a react app that utilizes Cognito for user authentication. My main query revolves around making a call to Cognito using the refresh token in order to receive a new token. Despite researching various examples provided by Cognit ...

The issue with the Hidden Content feature in the Slick Carousel is that it does not function correctly on the

There are some related topics worth exploring, such as: Slick carousel center class not working when going from last item to first item Despite trying various solutions, the issue still persists in my code. My goal is to have each item displayed in the ce ...

Transferring multiple sets of data from Firestore to another collection proves to be ineffective

Currently, I have four separate collections stored in my firestore database: EnglishQuestions MathQuestions ScienceQuestions DzongkhaQuestions My goal is to consolidate all the data from these individual collections and organize it under one collection f ...

One effective way to utilize await/async within the Vue mounted lifecycle hook is by

I am facing an issue where the mapGetters value is showing null in my computed property because the preferences method is not executed completely. I need to wait until the store has set the getter and setter. I have tried using async/await but it's no ...

ReactJS component disappearing behind the Navbar

When using my React app, I have a navigation bar at the top. The Navbar component is called in App.js, and the code snippet below shows how it is implemented. export default function App() { return ( <Router> <Fragment> ...

Disabling the Entire Page Using Jquery

I've got this cool ajax function function do_ajax_request(t){ var form = $('#edit_'+t); var loadingDiv = $('#loading_'+t); $.ajax({ url: form.attr("action"), type: "POST", data: form.serialize(), cach ...

Does utilizing this.someFunction.bind(this) serve a purpose or is it duplicative

As I analyze someone's code, I stumbled upon the following snippet: this.device_name.changes().onValue(this.changeName.bind(this)) My interpretation so far is that onValue requires a callback function, which in this case is this.changeName.bind(this ...

Stop Jade from collapsing the directory hierarchy

When it comes to implementing a build solution using NPM scripts instead of Gulp or Grunt, I have been facing some challenges in managing multiple Jade files efficiently. I've referred to resources like and for guidance. The Jade CLI allows for com ...

Asynchronous JavaScript function within a loop fails to refresh the document object model (DOM) despite

I have been working on a function that utilizes ajax to retrieve instructions from a backend server while the page is loading. The ajax code I've written retrieves the instructions based on the number provided and displays them using the response.setT ...

Unable to bind to ngModel as it returned as "undefined" in Angular 8

Whenever I bind a property to ngModel, it consistently returns undefined <div> <input type="radio" name="input-alumni" id="input-alumni-2" value="true" [(ngModel) ...

Drop and drag the spotlight

On my website, I am looking to implement a feature that will make it easier for users to identify the drag and drop area. I found a code snippet on JSFIDDLE that works perfectly there. However, when I tried to use it on my local server, it doesn't se ...

Is there a way to execute a jar file using JavaScript?

Hello, I'm new to this and still learning. I have a jar file that takes one parameter and returns a JSON with the result. Could someone please advise me on how to run my jar using JavaScript? I've attempted the following code but it's not wo ...

use ajax to dynamically load a section of the webpage based on filter criteria

I need to implement a search filter using 3 checkboxes. The search results will be displayed in the div with the id=posts_results <div class="checkbox"> <label><input type="checkbox" id="id1" class="typePost" value="En groupe"> ...

JavaScript - Retrieve the name of an object from a separate array

Is it possible to dynamically map rows and columns in a table component using arrays of objects? For example, I have two arrays of objects like this: const columnData = [ { id: 'name', label: 'Name' }, { id: 'value', lab ...

Utilizing Axios to filter response.data in an API request

Looking to retrieve the latest 8 products based on their date? Take a look at the code snippet below: const newestProducts= []; axios.get("http://localhost:3003/products").then(response => { let products = response.data.sort(fu ...

"Exploring the process of retrieving data from a request in Node.js with the help of the Express

I'm encountering some issues with integrating a "login" form into my Node.js script. While I can get it to work using a static HTML page, utilizing a dynamic ".ejs" page is causing trouble as my form fields are showing up as "undefined". var helmet = ...