I just saw this in the docs:
async function getData() {
const res = await fetch('https://api.example.com/...')
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
if (!res.ok) {
// This will activate the closest `error.js` Error Boundary
throw new Error('Failed to fetch data')
}
return res.json()
}
export default async function Page() {
const data = await getData()
return <main></main>
}Up to now, any time i've had fetching i've done a useEffect (and then marked the component as 'use client'). I've always figured this reduces performance, but the site seems to work fine. But now i'm looking at this and wondering when i should be doing this type of thing instead?
Also with this example above, if i host this on vercel, what does it count towards usage-wise? Edge Functions? Edge Middleware? Serverless Function Execution?
reactjs - next.js13 fetching data with an async function and also use state? - Stack Overflow
reactjs - How to implement useEffect in the server in Next.JS 14? - Stack Overflow
How to use async functions in useEffect (with examples)
Run async code in nextjs component without using UseEffect
Videos
In the next 13 app router, you need to choose whether a component is a server component (only runs on server) or a client component (runs in browser). Components using hooks such as useState must be client components. On the other hand, only server components can be async. At the moment you're trying to use both at the same time, so its invalid.
So one option is to turn your existing ProductDetails component into a bona fide client component by removing the async keyword and moving the fetching into useEffect to avoid fetching on every render (or better yet, use a fetching library such as react-query or swr).
Alternatively, you could make ProductDetailsFetcher an async server component which fetches the data, then passes the product as a prop to a client component which does the rendering. Only the client component would have useState.
The best option may depend on how getProduct is intended to be used - i.e. whether it designed to be run on the client or server.
Try loading getProduct via '@/sanity/sanity-utils' using a useEffect.
export default async function ProductDetails({ params }) {
const slug = params.product;
const [product, setProduct] = useState();
useEffect(() => {
getProduct(slug)
.then(res => res.json())
.then(data => setProduct(data))
.catch(err => console.log(err));
}, [] /* [] means it will load only once when component is mounted */)
console.log("product",product)
return (JSX)
}
You're probably asking this because you want to use the default SSR in NextJS and it doesn't work with useEffect code.
Think of useEffect as a hacky way of awaiting for async functions. NextJS SSR components can be async, so, there's no reason to use useEffect. Some example
Client component
This code would error because Home is not async
export function Home() {
const foo = await someAsyncFunction();
return <h1>{foo}</h1>
}
Then you'd fix it with
export function Home() {
const [foo, setFoo] = useState<string>("");
const fetchFoo = async () => {
const foo = await someAsyncFunction();
setFoo(foo);
}
useEffect(() => {fetchFoo});
return <h1>{foo}</h1>
}
SSR component
In server rendered components, you don't need all the hacky stuff. Just make the component async.
export async function Home() {
const foo = await someAsyncFunction();
return <h1>{foo}</h1>
}
UseEffect is actually a client side hook. You cannot use it on the server. You have to make that component a client component to use hooks like useEffect, useState, any click events, any form events etc.
You can make a component client by writing "use client" on top of your code ie, first line.
Be aware - using a use client directive will make all child components client components and will be rendered on user side, affecting some performance, so it is advised to keep your client components at the leaves of your tree.
By: joulev
What is the best practice for fetching data in a client component in Next.js 14?
route handlers with data fetching libraries, such as react-query or swr.
Is it acceptable to use server actions within useEffect for data fetching in a client component, or should I strictly use Route handlers for this purpose?
no, see below. it's best to use data fetching libraries, but if you really want you can still use useEffect โ but route handlers are required. why? see below.
Are there any performance or architectural considerations I should be aware of when choosing between these methods?
server actions cannot be run in parallel, so that completely disqualifies them from being a good data querying method.
Now could be used SWR in place of useEffect:
from https://nextjs.org/docs/pages/building-your-application/data-fetching/client-side
npm i swr
import useSWR from 'swr'
const fetcher = (...args) => fetch(...args).then((res) => res.json())
function Profile() {
const { data, error } = useSWR('/api/profile-data', fetcher)
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return (
<div>
<h1>{data.name}</h1>
<p>{data.bio}</p>
</div>
)
}