fetching data in a server component behaves differently than fetching in client component
Unanswered
Chinese Alligator posted this in #help-forum
Chinese AlligatorOP
I'm very new to Next, and i was watching a course which i think might be outdated, now the problem is:
- I have a fully working api, that behaves exactly how i want it to ( uses mongodb to send an array of objects, which are estate listings - this was the course project)
- I have the following code
I'm using const {properties} = fetch() because for some reason using this in a serverside component generates an object like:
- I have a fully working api, that behaves exactly how i want it to ( uses mongodb to send an array of objects, which are estate listings - this was the course project)
- I have the following code
import React from "react";
import PropertyCard from "@/components/PropertyCard";
const PropertiesPage = () => {
const fetchData = async () => {
try {
const res = await fetch(`http://localhost:3000/api/properties`);
if (!res.ok) {
throw new Error("Failed to fetch data");
}
return await res.json();
} catch (error) {
console.error("Error fetching properties:", error);
}
};
const {properties} = fetch()
return (
<section className="px-4 py-6">
<div className="container-xl lg:container m-auto px-4 py-6">
{properties.length === 0 ? (
<p>No properties found</p>
) : (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{properties.map((property) => (
<PropertyCard key={property._id} property={property} />
))}
</div>
)}
</div>
</section>
);
};
export default PropertiesPage;I'm using const {properties} = fetch() because for some reason using this in a serverside component generates an object like:
{properties:[ /* the actual array i need*/]} 142 Replies
Chinese AlligatorOP
This is the the clientside version of the component which works and fetches it as an array directly
It's somewhat different but should work the same, can please someone help me with this I can't wrap my head around why the client version works and the server doesnt and I'm sorry if I did some mistakes I have litterally been brainstorming this for the last hour.
"use client";
import React, { useState, useEffect } from "react";
import PropertyCard from "@/components/PropertyCard";
const PropertiesPage = () => {
const [properties, setProperties] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch(`http://localhost:3000/api/properties`);
if (!res.ok) {
throw new Error("Failed to fetch data");
}
const data = await res.json();
setProperties(data);
} catch (error) {
console.error("Error fetching properties:", error);
}
};
fetchData();
}, []);
return (
<section className="px-4 py-6">
<div className="container-xl lg:container m-auto px-4 py-6">
{properties.length === 0 ? (
<p>No properties found</p>
) : (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{properties.map((property) => (
<PropertyCard key={property._id} property={property} />
))}
</div>
)}
</div>
</section>
);
};
export default PropertiesPage;It's somewhat different but should work the same, can please someone help me with this I can't wrap my head around why the client version works and the server doesnt and I'm sorry if I did some mistakes I have litterally been brainstorming this for the last hour.
@"use php" and I think the function should be `fetchData` & not `fetch`
Chinese AlligatorOP
yes that was not the error just some typo because i 'ctrl z' d to get to the version using server component :D
i m looking over the link you sent and i will be back soon\
@"use php" https://nextjs-faq.com/fetch-api-in-rsc
Chinese AlligatorOP
This article says i should not be fetching my own endpoint in a server component, but was this possible in previous versions of next? because as i said my tutorial might be slightly outdated.
The reason I'm asking this is because I don't know whether the guy in the tutorial will use specifical server component code inside the one i will be constrained to keep as clientside, does this make sense?
The reason I'm asking this is because I don't know whether the guy in the tutorial will use specifical server component code inside the one i will be constrained to keep as clientside, does this make sense?
Use a function then instead
@"use php" It is possible, but you should not
Chinese AlligatorOP
then i would like to know how to actually solve what i m doing wrong
I'll let you know about erro
Chinese AlligatorOP
i don t really understand the array thing
Chinese AlligatorOP
in the serverside version?
yes
I think the "array thing" you are talking about is pretty easy to understand, you're prolly returning a json object in the api as something like this :
So, when you do
Also, as mentioned in the above link, don't fetch your own api in server components, directly do the db thingy it in the server component itself.
{properties: [], ...other things}. So, when you do
res.json() you get the object, not the array.Also, as mentioned in the above link, don't fetch your own api in server components, directly do the db thingy it in the server component itself.
Chinese AlligatorOP
import React from "react";
import PropertyCard from "@/components/PropertyCard";
async function fetchProperties() {
try {
const res = await fetch(`http://localhost:3000/api/properties`);
if (!res.ok) {
throw new Error("failed to fetch data");
}
const data = res.json();
return data;
} catch (error) {
console.log(error);
}
}
const PropertiesPage = async () => {
const properties = await fetchProperties();
return (
<section className="px-4 py-6">
<div className="container-xl lg:container m-auto px-4 py-6">
{console.log(properties)}
{/* {properties.length === 0 ? (
<p>No properties found</p>
) : (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{properties.map((property) => (
<PropertyCard key={property._id} property={property} />
))}
</div>
)} */}
</div>
</section>
);
};
export default PropertiesPage; this is the latest code of the server component, the first one is not correctasync function fetchProperties() {
try {
const res = await fetch(`http://localhost:3000/api/properties`);
if (!res.ok) {
throw new Error("failed to fetch data");
}
const data = res.json();
return data;
} catch (error) {
console.log(error);
}
}properties is a object
this doesn't look correct
you'll have to const { properties }
why hit your api route? query out db directly in this function
@James4u why hit your api route? query out db directly in this function
Chinese AlligatorOP
i don't know anything about mongodb i ll just pick and go but i need a fix to this so i can move forward with the tutorial
@"use php" properties is a object
Chinese AlligatorOP
if i actually go to localhost:3000/api/properties i get this
which is not an object
That means the fetch request is most likely cached
you can
export revalidate = 0Chinese AlligatorOP
that s what i was thinking but in the 'use client' version i first provided it updates everytime i do a change in the database
its because of cache
i guess
@"use php" you can
ts
export revalidate = 0
Chinese AlligatorOP
where do i put this
i have no idea
page.tsx && route.ts
You can customise it later on
Chinese AlligatorOP
i need to replace the default export with this or what?
just put this below imports
Chinese AlligatorOP
'Declaration or statement expected'
in both files
i use js not ts but it doesnt have anything to do with this
@Chinese Alligator where do i put this
export const revalidate = 0mb
Chinese AlligatorOP
there is no way i could actually call you real quick and discuss this? i hope this doesnt break any guidelines
because i genuinely don t understand
@Chinese Alligator there is no way i could actually call you real quick and discuss this? i hope this doesnt break any guidelines
Chinese AlligatorOP
just so i could sharescreen
@"use php"
I recommend you to take a look at the doc
@Chinese Alligator Click to see attachment
is this from the db? or any external api?
Chinese AlligatorOP
from db
and do you know how frequent it is changing?
okay then this
Chinese AlligatorOP
quick question
I believe if you move querying part into your function, your issue will be solved
the reason you get cached response is because next.js automatically cache GET route
move the querying logic you have in
/api/properties into your fetch functionand that's the correct practice
Chinese AlligatorOP
import connectDb from "@/config/database";
import Property from "@/models/Property";
export const revalidate = 0;
// GET /api/properties
export const GET = async () => {
try {
await connectDb();
const properties = await Property.find();
return new Response(JSON.stringify(properties), {
status: 200,
});
} catch (error) {
console.log(error);
return new Response("Didn't work", { status: 500 });
}
};
import Property from "@/models/Property";
export const revalidate = 0;
// GET /api/properties
export const GET = async () => {
try {
await connectDb();
const properties = await Property.find();
return new Response(JSON.stringify(properties), {
status: 200,
});
} catch (error) {
console.log(error);
return new Response("Didn't work", { status: 500 });
}
};
this is what i have in properties
yeah, have this code part in your fetch function
fetchPropertiesChinese AlligatorOP
import React from "react";
import PropertyCard from "@/components/PropertyCard";
async function fetchProperties() {
const connect = async () => {
try {
await connectDb();
const properties = await Property.find();
return new Response(JSON.stringify(properties), {
status: 200,
});
} catch (error) {
console.log(error);
return new Response("Didn't work", { status: 500 });
}
};
try {
await connect();
const res = await fetch(`http://localhost:3000/api/properties`);
if (!res.ok) {
throw new Error("failed to fetch data");
}
const data = res.json();
return data;
} catch (error) {
console.log(error);
}
}
const PropertiesPage = async () => {
const { properties } = await fetchProperties();
return (
<section className="px-4 py-6">
<div className="container-xl lg:container m-auto px-4 py-6">
{properties.length === 0 ? (
<p>No properties found</p>
) : (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{properties.map((property) => (
<PropertyCard key={property._id} property={property} />
))}
</div>
)}
</div>
</section>
);
};
export default PropertiesPage;is this correct? it doesnt work still
try console properties? still get cached one?
no no @Chinese Alligator , why are you still hitting your endpoint?
async function fetchProperties() {
try {
await connectDb();
const properties = await Property.find();
return new Response(JSON.stringify(properties), {
status: 200,
});
} catch (error) {
console.log(error);
return new Response("Didn't work", { status: 500 });
}
}
}Chinese AlligatorOP
i m just trying to work around this method right now so i can follow with the course, hitting my own endpoint is possible but not a good practice right?
also, use relative url. not absolute
can't use relative url in the server side data fetching @averydelusionalperson
Chinese AlligatorOP
i m in a server component
relative url is only available in client side data fetching
oh right
sorry
and @Chinese Alligator we don't need to hit our api endpoint as we are using server component
@James4u and <@217546517509046273> we don't need to hit our api endpoint as we are using server component
Chinese AlligatorOP
are you suggesting the usage of a client side component?
Nope @Chinese Alligator
@Chinese Alligator are you suggesting the usage of a client side component?
no, just do the data fetching in server component instead of writing different api route for that
Chinese AlligatorOP
oh i see
but it s not the only component that needs this fetch
then write a reusable function
it's okay then
abstract this fetching logic as an async function
and reuse it everywhere you need this logic
Chinese AlligatorOP
alright but the scope of the tutorial is going to be of me learning how to actually use api routes
are you on app router guide?
then abandon that tutorial
which tutorial are you referring?
Chinese AlligatorOP
it s a udemy course
by brad traversy
@averydelusionalperson then abandon that tutorial
Chinese AlligatorOP
this would actually be a great idea but i can t find any good courses to start with in next
I don't really think there is anything to learn in "API routes"
@James4u or Brad Traversy
Chinese AlligatorOP
yes i don t really use capital letters lol
he did not, it s just probably outdated
Chinese AlligatorOP
because in the tutorial this actually runs
maybe checkout javascript mastery yt channel
ofc, it
worksChinese AlligatorOP
idk i d genuinely like a course with typescript instead of this
udemy isn't good man
yt and docs way better
@averydelusionalperson yt and docs way better
Chinese AlligatorOP
courses are better than docs mostly because you actually have something to work on
anyway i think i m abandoning the course if you still want to talk we can talk on #off-topic
Chinese AlligatorOP
i genuinely cant find the reason why it works on a client component
but not on a server component
me too, it shouldn't work on both
Chinese AlligatorOP
and if it s caching
what was your original issue? actually I have no idea what was your original pain
I just pointed out some practical mistakes
just do
Response.json(... your data)Chinese AlligatorOP
i changed it and it still doesnt work
try this:
Response.json({properties})Chinese AlligatorOP
lol this is cached
Chinese AlligatorOP
i just tried to do
return new Response("asd", {
status: 200,
});
return new Response("asd", {
status: 200,
});
and it still displays with no errors on website
do hard cache reload
Chinese AlligatorOP
how?
ctrl + shift + rChinese AlligatorOP
i can t follow along with this, i will try to use an older version from git and redo the tutorial
i m genuinely tired i have been doing this all day
take a break lol
we all have been there
Chinese AlligatorOP
yep i m coming back tommorow
2 days later
the OP said he's gonna do some other tutorial.... so this thread is closed ig
