useEffect(()=>{}, []) is called every time page is visited
Answered
Yellow and black potter wasp posted this in #help-forum
Yellow and black potter waspOP
Since I want to fetch some data from the database in initial visit then I wrap that into
But each time I visit that page this will get triggered, in another words for each route visit page is being mounted..
How to solve this?
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?
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
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
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)
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 tried now with this code for `app/page.tsx`:
js
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)
It's not a good way of thinking, that the balance should be handled by the client only because it will be updated very often. Else banks and payment services will have a very big problem. So keep it serverside. You can cache and invalidate your page if needed directly after something changes [(see here)](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating)
@B33fb0n3 It's not a good way of thinking, that the balance should be handled by the client only because it will be updated very often. Else banks and payment services will have a very big problem. So keep it serverside. You can cache and invalidate your page if needed directly after something changes [(see here)](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating)
Yellow and black potter waspOP
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
@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:
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
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
@Yellow and black potter wasp But even with that it's the problem.. Let's say I have client component:
js
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
yes, then save the new data either in interval or when there is a specific action (for example the user leaves the page)
@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 wasp 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?
you can use the [beforeunload event](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event) to check if the client leaves the page. Then simply save your stuff inside this event and you should be good to go 👍
@B33fb0n3 you can use the [beforeunload event](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event) to check if the client leaves the page. Then simply save your stuff inside this event and you should be good to go 👍
Yellow and black potter waspOP
Already tried that.. A lot of problems, mobile users not detecting at all..
@Yellow and black potter wasp Already tried that.. A lot of problems, mobile users not detecting at all..
alright, then take a look at the [visibilitychange event](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event). That will reliably be fired. This is a possible implementation: https://www.igvita.com/2015/11/20/dont-lose-user-and-app-state-use-page-visibility/
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 js
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?
you might want to
await the data saving. Else you get redirected while saving and that may end up in data loss@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>
)