Next.js Discord

Discord Forum

useEffect(()=>{}, []) is called every time page is visited

Answered
Yellow and black potter wasp posted this in #help-forum
Open in Discord
Yellow and black potter waspOP
Since I want to fetch some data from the database in initial visit then I wrap that into
useEffect(() => {
  fetch...
}, []);

But each time I visit that page this will get triggered, in another words for each route visit page is being mounted..
layout.tsx:
"use client";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";

import Link from "next/link";

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>

      <nav>
        <Link href="/">
          Home
        </Link>
        <Link href="/edit">
          Edit
        </Link>
      </nav>
        <main>{children}</main>
      </body>
    </html>
  );
}

app/page.tsx:
"use client";

import styles from "./page.module.css";
import { useEffect } from "react";

export default function Home() {
  useEffect(() => {
    console.log('Home init');
  }, []);

  return (
    <main className={styles.main}>
      <h1>Home</h1>
    </main>
  );
}

app/edit/page.tsx:
'use client';

import { useEffect } from "react";

export default function Edit() {
  useEffect(() => {
    console.log('Edit init');
  }, []);

  return (
    <div>
      <h1>Edit Page</h1>
    </div>
  );
}

How to solve this?
Answered by Yellow and black potter wasp
const router = useRouter();

const onHomeBtnClicked = () => {
  saveData(); // save data into the database
  router.push('/');
};
// and also for each of the page (I have 4 of them)

return (
  ...
        <div className={styles.bottomNavMenu}>
          <div className={`${styles.activeTab} ${styles.tabLink}`}>Home</div>
          <div className={styles.tabLink} onClick={earnBtnClicked}>Earn</div>
          <div className={styles.tabLink} onClick={friendBtnClicked}>Friend</div>
          <div className={styles.tabLink} onClick={marketBtnClicked}>Market</div>
        </div>

This works fine, but are there any side effects of this approach?
View full answer

24 Replies

@Yellow and black potter wasp Since I want to fetch some data from the database in initial visit then I wrap that into js useEffect(() => { fetch... }, []); But each time I visit that page this will get triggered, in another words for each route visit page is being mounted.. `layout.tsx`: js "use client"; import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; import Link from "next/link"; const inter = Inter({ subsets: ["latin"] }); export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { return ( <html lang="en"> <body className={inter.className}> <nav> <Link href="/"> Home </Link> <Link href="/edit"> Edit </Link> </nav> <main>{children}</main> </body> </html> ); } `app/page.tsx`: js "use client"; import styles from "./page.module.css"; import { useEffect } from "react"; export default function Home() { useEffect(() => { console.log('Home init'); }, []); return ( <main className={styles.main}> <h1>Home</h1> </main> ); } `app/edit/page.tsx`: js 'use client'; import { useEffect } from "react"; export default function Edit() { useEffect(() => { console.log('Edit init'); }, []); return ( <div> <h1>Edit Page</h1> </div> ); } How to solve this?
you can solve this by fetching on the server and passing it down to the client.

Another thing your might want to consider is to use cache if you don't want to fetch everything again on each visit.

And if you ever need to fetch on clientside (normally you don't on initial render), you should use a clientside fetching library like swr or react query, to control your data
@B33fb0n3 you can solve this by fetching on the server and passing it down to the client. Another thing your might want to consider is to use cache if you don't want to fetch everything again on each visit. And if you ever need to fetch on clientside (normally you don't on initial render), you should use a clientside fetching library like swr or react query, to control your data
Yellow and black potter waspOP
I tried now with this code for app/page.tsx:
import styles from "./page.module.css";
import { useEffect } from "react";

export default function Home() {
  console.log('Hello');

  return (
    <main className={styles.main}>
      <h1>Home</h1>
    </main>
  );
}

And 'Hello' is being called sometimes when I go to the main page of the app, so even with this approach that initial data fetch point wouldv'e been lost.. For example if I'm fetching the balance in initial visit, and user is buying something and that balance is being updated in the frontend and if he goes back to the main page he will have initial balance (consider that balance for the game will be updated very often so there is no point of updating the database each time the balance is changed so instead it's updated in the frontend and at the end it's updated in the database)
@Yellow and black potter wasp I know that is not good idea, that's why I said it's a game.. Not so important.. And balance can change few times within a second, and other parameters as well, so I would be having thousands of request in 1 min by 1 user
If security is not really important for you, then you can make it via clientside states: Fetch on the server, pass it down via props and modify the clientside state. Then save the new data either in interval or when there is a specific action
@B33fb0n3 If security is not really important for you, then you can make it via clientside states: Fetch on the server, pass it down via props and modify the clientside state. Then save the new data either in interval or when there is a specific action
Yellow and black potter waspOP
But even with that it's the problem.. Let's say I have client component:
export default ClientComponent({ data }: ClientComponentProps) {
  const { coins } = data;
  const [coinsData, setCoinsData] = useState(coins);

  const updateCoins = () => {
    setCoinsData(coinsData + 1);
  }

  return (
    <>
      <p>Coins: {coinsData}</p>
      <button onClick={updateCoins}>Update</button>
    </>
  )
};

When I'm on this page this works, but as soon as I leave the page and I go back to this page this will be updated and coins will be the ones from the database
@B33fb0n3 yes, then save the new data either in interval or when there is a specific action (for example the user leaves the page)
Yellow and black potter waspOP
I've been trying for so long to find the answer to this topic on user leaving the page but I couldn't find one.. Do you have any docs or examples how to achieve this?
Yellow and black potter waspOP
useEffect(() => {
    return () => {
        // changed route kinda
    };
}, []);

This somehow works.. But this is called twice, once in visit and once when user leaves the page.. So I can use state to check, in first one will set to true and then in second one will do the work
const [leaving, setLeaving] = useState(false);
useEffect(() => {
  return () => {
    if(leaving) {
      //...
    } else {
      setLeaving(true);
    }
  }
}, []);

Is this kinda ok?
Yellow and black potter waspOP
Not even this works..
Yellow and black potter waspOP
Not firing when pages switching
I don't know anymore.. This is getting crazy
then sync it on other user actions. Get creative and provide the best experience for your client
@B33fb0n3 then sync it on other user actions. Get creative and provide the best experience for your client
Yellow and black potter waspOP
const router = useRouter();

const onHomeBtnClicked = () => {
  saveData(); // save data into the database
  router.push('/');
};
// and also for each of the page (I have 4 of them)

return (
  ...
        <div className={styles.bottomNavMenu}>
          <div className={`${styles.activeTab} ${styles.tabLink}`}>Home</div>
          <div className={styles.tabLink} onClick={earnBtnClicked}>Earn</div>
          <div className={styles.tabLink} onClick={friendBtnClicked}>Friend</div>
          <div className={styles.tabLink} onClick={marketBtnClicked}>Market</div>
        </div>

This works fine, but are there any side effects of this approach?
Answer
@Yellow and black potter wasp solved?
@B33fb0n3 <@452547952213491723> solved?
Yellow and black potter waspOP
Sorry I forgot to reply.. That solved it, thanks a lot
@Yellow and black potter wasp Sorry I forgot to reply.. That solved it, thanks a lot
That sounds great. Please mark solution
@B33fb0n3 That sounds great. Please mark solution
Yellow and black potter waspOP
Sorry I'm new to this community, what does mark solution mean?
@Yellow and black potter wasp Sorry I'm new to this community, what does mark solution mean?
Which message helped you the most and resolved your initial issue the most?
@B33fb0n3 then sync it on other user actions. Get creative and provide the best experience for your client
Yellow and black potter waspOP
This approach with navigating to other pages through <button> instead of <Link> component and saving the data in async function to await the data save, so final code would've been:
const homeBtnClicked = () => {
  saveData(); // save data into the database
  router.push('/');
};

const earnBtnClicked = () => {
  saveData(); // save data into the database
  router.push('/earn');
};

const friendBtnClicked = () => {
  saveData(); // save data into the database
  router.push('/friend');
};

const marketBtnClicked = () => {
  saveData(); // save data into the database
  router.push('/market');
};

return (
  <div>
    <button onClick={homeBtnClicked}>Home</button>
    <button onClick={earnBtnClicked}>Earn</button>
    <button onClick={friendBtnClicked}>Friend</button>
    <button onClick={marketBtnClicked}>Market</button>
  </div>
)