Having issues with server side fetching;
Answered
Collared Plover posted this in #help-forum
Collared PloverOP
The API route functions perfectly; however, the prop returned from getStaticProps() is undefined, and I have no idea why, plz help.
96 Replies
if you're using app router,
getStaticProps doesn't work thereCollared PloverOP
I dont understand, I'm not directly using it inside the app router, i
@Anay-208 if you're using app router, `getStaticProps` doesn't work there
Collared PloverOP
I dont understand, I'm not directly using it inside the app router,
@Collared Plover I dont understand, I'm not directly using it inside the app router,
getStaticProps is not in app router, it’s only in pages router. Means getStaticProp won’t be executed in app router
Fetch data from server component then pass to client component
@Anay-208 getStaticProps is not in app router, it’s only in pages router. Means getStaticProp won’t be executed in app router
Collared PloverOP
I've placed the "recentProjects" component inside the ui folder and I'm calling the component inside the projects route. I sort of understand what you mean. For example, if I mark the RecentProjects file with 'use server', it gives me errors. Why is RecentProjects considered a client component? I really appreciate you taking the time to help me out. Thank you. Look here:
@Collared Plover I've placed the "recentProjects" component inside the ui folder and I'm calling the component inside the projects route. I sort of understand what you mean. For example, if I mark the RecentProjects file with 'use server', it gives me errors. Why is RecentProjects considered a client component? I really appreciate you taking the time to help me out. Thank you. Look here:
Why are you using use client here? set the parent component to use server and pass the data to client component
@Anay-208 Why are you using use client here? set the parent component to use server and pass the data to client component
Collared PloverOP
I get what you're saying. You mentioned that "getStaticProps" isn't available in the app router, only in the pages router. But now that the pages router has been replaced with the app router, what should I do?
@Collared Plover I get what you're saying. You mentioned that "getStaticProps" isn't available in the app router, only in the pages router. But now that the pages router has been replaced with the app router, what should I do?
Use server component to fetch data and pass it to client component
If you didn’t get that, I’ll explain in detail
Move logic of getStaticProps to server component
And use it there
And pass it as props to client component
@Anay-208 If you didn’t get that, I’ll explain in detail
Collared PloverOP
oh i see,
@Anay-208 And pass it as props to client component
Collared PloverOP
I did exactly what you suggested. However, I encountered the error message "Error: async/await is not yet supported in Client Components, only Server Components," I don't understand its meaning. The only place I added "use client" is in the main projects route. When I remove this "use client," it then gives me the error "create context is not a function." Please check the attached pictures.
its because page.tsx a client component
Collared PloverOP
I removed the async function from RecentProjects and made it a normal function. The error "async/await is not yet supported in Client Components, only Server Components" is gone. However, now I'm facing the issue of my data being undefined. I'll attach my API route and how I'm fetching data.
make page.tsx a server component
set page.tsx as server components
and fetch data here
like prisma.findOne()
American Crow
If you have knowledge of Nextjs Pages Router you may want to read through the entire migration documentation so you know what changed.
Here is the part with getStaticProps but I'd recommand giving the whole page a good read to gain some understanding:
https://nextjs.org/docs/pages/building-your-application/upgrading/app-router-migration#static-site-generation-getstaticprops
Here is the part with getStaticProps but I'd recommand giving the whole page a good read to gain some understanding:
https://nextjs.org/docs/pages/building-your-application/upgrading/app-router-migration#static-site-generation-getstaticprops
So your mental model can adapt to the new way of doing things
@American Crow So your mental model can adapt to the new way of doing things
Collared PloverOP
I will do so thanks;
@Anay-208 make page.tsx a server component
Collared PloverOP
when i set page.tsx i get "create context is not a function".
@Collared Plover when i set page.tsx i get "create context is not a function".
did you fetch the projects in the server component?
Collared PloverOP
Yes i did, plz look at the attached image.
@Anay-208 did you fetch the projects in the server component?
Collared PloverOP
Yes i did, plz look at the attached image.
@Collared Plover Yes i did, plz look at the attached image.
See, you're using getstaticprops
if you're importing this
function
some where else
call this function, and use
.props.projects to get the projects@Anay-208 See, you're using getstaticprops
Collared PloverOP
Would you please be willing to demonstrate what you mean with an implementation or provide an example code? I would greatly appreciate it if you could do this for me.
1 min
// app/route/page.tsx
"use server";
export default async function Page(){
// search data
const data = await prisma.findOne()
return (
<MyComponent data={data}/>
)
}also, see this https://nextjs-faq.com/fetch-api-in-getserversideprops (just an example)
@Anay-208 SURE
Collared PloverOP
Quick question: How are you able to type code?
@Collared Plover Quick question: How are you able to type code?
mark my message as a solution if your issue is resolved
@Anay-208 mark my message as a solution if your issue is resolved
Collared PloverOP
i will gladly do
@Anay-208 js
// app/route/page.tsx
"use server";
export default async function Page(){
// search data
const data = await prisma.findOne()
return (
<MyComponent data={data}/>
)
}
Collared PloverOP
export async function fetchProjects() {
try {
if (!project) await connectToCollection();
if (!project) throw new Error("Projects not initialized.");
const result = await project.find({}).limit(10).toArray();
return { result };
} catch (error) {
console.error("Failed to fetch projects:", error);
return { error: "Failed to fetch projects!" };
}
}So I should implement this code directly in getstaticProps?
@Collared Plover tsx
export async function fetchProjects() {
try {
if (!project) await connectToCollection();
if (!project) throw new Error("Projects not initialized.");
const result = await project.find({}).limit(10).toArray();
return { result };
} catch (error) {
console.error("Failed to fetch projects:", error);
return { error: "Failed to fetch projects!" };
}
}
So I should implement this code directly in getstaticProps?
If this is your function, import it to server component, execute it, and give its output to the child component
Collared PloverOP
I think it's already running on the server, i'm querying my database in a data.ts file
"use server";
import { MongoClient } from "mongodb";
import { Collection, Document } from "mongodb";
const uri = process.env.MONGODB_URI || ""; // Provide a fallback value of an empty string
const options = {};
let mongoClient: MongoClient | undefined; // Specify the type of mongoClient as MongoClient | undefined
if (!uri) {
throw new Error("Please add your Mongo URI to .env");
}
export async function connectToDatabase() {
try {
// Check if MongoClient is already instantiated to ensure singleton behavior
if (mongoClient) {
return { mongoClient };
}
// Create a new MongoClient instance and connect to the database
mongoClient = await new MongoClient(uri, options).connect();
console.log("Connected to Database!");
// Return the connected MongoClient instance
return { mongoClient };
} catch (error) {
console.error("Error connecting to MongoDB:", error);
throw error; // Rethrow the error to propagate it to the caller
}
}
let project: Collection<Document>;
async function connectToCollection() {
try {
const { mongoClient } = await connectToDatabase();
const db = mongoClient.db("GeekGalore");
project = db.collection("Projects");
} catch (e) {
console.error("Failed to connect to database:", e);
throw new Error("Failed to connect to database.");
}
}
export async function fetchProjects() {
try {
if (!project) await connectToCollection();
if (!project) throw new Error("Projects not initialized.");
const result = await project.find({}).limit(10).toArray();
return { result };
} catch (error) {
console.error("Failed to fetch projects:", error);
return { error: "Failed to fetch projects!" };
}
}
export default async function handler() {
try {
await connectToCollection();
} catch (e) {
console.error("Failed to connect to database:", e);
throw new Error("Failed to connect to database.");
}
}@Anay-208 If this is your function, import it to server component, execute it, and give its output to the child component
Collared PloverOP
"use server";
import { MongoClient } from "mongodb";
import { Collection, Document } from "mongodb";
const uri = process.env.MONGODB_URI || ""; // Provide a fallback value of an empty string
const options = {};
let mongoClient: MongoClient | undefined; // Specify the type of mongoClient as MongoClient | undefined
if (!uri) {
throw new Error("Please add your Mongo URI to .env");
}
export async function connectToDatabase() {
try {
// Check if MongoClient is already instantiated to ensure singleton behavior
if (mongoClient) {
return { mongoClient };
}
// Create a new MongoClient instance and connect to the database
mongoClient = await new MongoClient(uri, options).connect();
console.log("Connected to Database!");
// Return the connected MongoClient instance
return { mongoClient };
} catch (error) {
console.error("Error connecting to MongoDB:", error);
throw error; // Rethrow the error to propagate it to the caller
}
}
let project: Collection<Document>;
async function connectToCollection() {
try {
const { mongoClient } = await connectToDatabase();
const db = mongoClient.db("GeekGalore");
project = db.collection("Projects");
} catch (e) {
console.error("Failed to connect to database:", e);
throw new Error("Failed to connect to database.");
}
}
export async function fetchProjects() {
try {
if (!project) await connectToCollection();
if (!project) throw new Error("Projects not initialized.");
const result = await project.find({}).limit(10).toArray();
return { result };
} catch (error) {
console.error("Failed to fetch projects:", error);
return { error: "Failed to fetch projects!" };
}
}
export default async function handler() {
try {
await connectToCollection();
} catch (e) {
console.error("Failed to connect to database:", e);
throw new Error("Failed to connect to database.");
}
}@Anay-208 If this is your function, import it to server component, execute it, and give its output to the child component
Collared PloverOP
I think it's already running on the server, that's my data.ts file with how I'm interracting with my database.
So shouldn’t the code be working?
@Collared Plover I think it's already running on the server, that's my data.ts file with how I'm interracting with my database.
If you’re importing and working with it correctly, it should work
@Anay-208 If you’re importing and working with it correctly, it should work
Collared PloverOP
Good day! I apologize, I experienced a power outage yesterday.
@Anay-208 If you’re importing and working with it correctly, it should work
Collared PloverOP
fetchproject.tsx
"use server";
import { fetchProjects } from "@/app/lib/data";
export async function getStaticProps() {
const { result } = await fetchProjects(); Function returns an array
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
if (!result) {
// This will activate the closest `error.js` Error Boundary
throw new Error("Failed to fetch data");
}
const Projects = result.json(); I get error: "Property 'json' does not exist on type 'WithId<Document>[]'.
return {
props: Projects,
};
}@Anay-208 If you’re importing and working with it correctly, it should work
Collared PloverOP
import { motion } from "framer-motion";
import Image, { StaticImageData } from "next/image";
import Link from "next/link";
import { GithubIcon } from "../icons";
import { Key } from "react";
import { getStaticProps } from "./fetchproject";
import { InferGetStaticPropsType } from "next";
const FramerImage = motion(Image);
export default function RecentProjects({
Projects,
}: InferGetStaticPropsType<typeof getStaticProps>) {
return (
<div className="col-span-8 grid w-full grid-cols-2 gap-16 xl:gap-12 sxl:col-span-12 sm:flex sm:flex-col sm:items-center sm:gap-0 sm:gap-y-16">
{Projects.result.map(
(project: {
_id: Key | null | undefined;
............"use server";
import { fetchProjects } from "@/app/lib/data";
export async function getStaticProps() {
const { result } = await fetchProjects(); Function returns an array
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
if (!result) {
// This will activate the closest `error.js` Error Boundary
throw new Error("Failed to fetch data");
}
const Projects = result.json(); I get error: "Property 'json' does not exist on type 'WithId<Document>[]'.
return {
props: Projects,
};
}Is it working?
@Anay-208 Is it working?
Collared PloverOP
Nope, please review the code I specified where I'm encountering issues. Although we've made progress, I'm currently facing an issue when iterating over the array returned from the fetchProjects function. Specifically, I'm encountering the error "Cannot read properties of undefined (reading 'map')". Additionally, earlier I encountered the error "Property 'result' does not exist on type 'WithId<Document>[]"
@Anay-208 Is it working?
Collared PloverOP
import { motion } from "framer-motion";
import Image, { StaticImageData } from "next/image";
import Link from "next/link";
import { GithubIcon } from "../icons";
import { Key } from "react";
import { getStaticProps } from "./fetchproject";
import { InferGetStaticPropsType } from "next";
const FramerImage = motion(Image);
export default function RecentProjects({
projects,
}: InferGetStaticPropsType<typeof getStaticProps>) {
return (
<div className="col-span-8 grid w-full grid-cols-2 gap-16 xl:gap-12 sxl:col-span-12 sm:flex sm:flex-col sm:items-center sm:gap-0 sm:gap-y-16">
{projects?.map((project: any) => (
<article
key={project._id}@Anay-208 Is it working?
Collared PloverOP
import { fetchProjects } from "@/app/lib/data";
export async function getStaticProps() {
try {
// Fetch projects data from your API route
const { result, error } = await fetchProjects();
if (error || !result) {
// If there's an error or no result, throw an error to activate the error boundary
throw new Error("Failed to fetch data");
}
// Return the projects data as props
return {
props: {
projects: result, // Assuming `result` is an array of projects data
},
};
} catch (error) {
// Catch any errors and log them
console.error("Error fetching projects:", error);
// Return an empty object if there's an error
return {
props: {
projects: [],
},
};
}
}share the function where you are using
RecentProjects@Anay-208 share the function where you are using `RecentProjects`
Collared PloverOP
"use client";
import { InferGetStaticPropsType } from "next";
import AnimatedText from "../ui/AnimatedText";
import Layout from "../ui/layout";
import FeaturedProjectTable from "../ui/project/FeaturedProjectTable";
import RecentProjects from "../ui/project/RecentProjects";
import { getStaticProps } from "../ui/project/fetchproject";
export default function Page() {
return (
<>
<main className="w-full mb-16 flex items-center justify-center overflow-clip dark:text-light">
<Layout className="px-0 xs:pt-10">
.............................................
<article className="py-16 dark:bg-[#121212]">
<div className="relative mx-32 flex flex-col justify-between lg:mx-14 md:mx-12 xs:mx-4">
<h2 className="my-8 block w-max border-b-4 border-solid border-purpledark font-ot text-4xl font-bold uppercase leading-snug tracking-wide dark:border-purple dark:text-light lg:text-3xl md:mx-auto md:w-max md:text-center md:text-2xl">
Recent Projects
</h2>
<article className="mt-20 grid w-full grid-cols-12 gap-16 xl:gap-8 lg:gap-0 lg:gap-y-8 md:gap-0 sm:gap-0 xs:gap-0 md:!gap-y-8">
<RecentProjects />
<FeaturedProjectTable />
</article>
</div>
</article>
</Layout>
</main>
</>
);
};and you've to fetch data from here
and pass it like this
<RecentProjects projects={projects}/> // will be added as a prop@Anay-208 This is supposed to be a server component
Collared PloverOP
When I remove the "use client" in this page component I get the error "Error: (0 , reactWEBPACK_IMPORTED_MODULE_0.createContext) is not a function"
import { InferGetStaticPropsType } from "next";
import AnimatedText from "../ui/AnimatedText";
import Layout from "../ui/layout";
import FeaturedProjectTable from "../ui/project/FeaturedProjectTable";
import RecentProjects from "../ui/project/RecentProjects";
import { getStaticProps } from "../ui/project/fetchproject";
export default function Page({
projects,
}: InferGetStaticPropsType<typeof getStaticProps>) {
return (
<>
<main className="w-full mb-16 flex items-center justify-center overflow-clip dark:text-light">
<Layout className="px-0 xs:pt-10">
.............................................
<article className="py-16 dark:bg-[#121212]">
<div className="relative mx-32 flex flex-col justify-between lg:mx-14 md:mx-12 xs:mx-4">
<h2 className="my-8 block w-max border-b-4 border-solid border-purpledark font-ot text-4xl font-bold uppercase leading-snug tracking-wide dark:border-purple dark:text-light lg:text-3xl md:mx-auto md:w-max md:text-center md:text-2xl">
Recent Projects
</h2>
<article className="mt-20 grid w-full grid-cols-12 gap-16 xl:gap-8 lg:gap-0 lg:gap-y-8 md:gap-0 sm:gap-0 xs:gap-0 md:!gap-y-8">
<RecentProjects projects={projects}/>
<FeaturedProjectTable />
</article>
</div>
</article>
</Layout>
</main>
</>
);
};@Collared Plover When I remove the "use client" in this page component I get the error "Error: (0 , react__WEBPACK_IMPORTED_MODULE_0__.createContext) is not a function"
you've to fix the error. Try seeing which package is causing that error.
@Anay-208 you've to fix the error. Try seeing which package is causing that error.
Collared PloverOP
Animated Text uses framer motion could this be causing the issue? tried getting rid of it but nothing
@Anay-208 set this component to "use client"
Collared PloverOP
After setting recentProjects to "use client" the error gone.
@Anay-208 set this component to "use client"
Collared PloverOP
"use client";
import { motion } from "framer-motion";
import Image, { StaticImageData } from "next/image";
import Link from "next/link";
import { GithubIcon } from "../icons";
import { Key } from "react";
import { getStaticProps } from "./fetchproject";
import { InferGetStaticPropsType } from "next";
const FramerImage = motion(Image);
export default function RecentProjects({
projects,
}: InferGetStaticPropsType<typeof getStaticProps>) {
return (
<div className="col-span-8 grid w-full grid-cols-2 gap-16 xl:gap-12 sxl:col-span-12 sm:flex sm:flex-col sm:items-center sm:gap-0 sm:gap-y-16">
{projects?.map((project: any) => (
<article
key={project._id}
className="ease paper flex h-max w-full flex-col overflow-hidden rounded-lg border dark:border-solid border-purpledark/50 bg-light transition-all duration-300 first:my-0 dark:border-purple/50 dark:bg-[#121212]">
<Linkand now, use server component to fetch data and pass it to client component
@Anay-208 and now, use server component to fetch data and pass it to client component
Collared PloverOP
Remember, you asked me to create a server component that contains getStaticProps and export it. I have done so, and I'm passing the prop in RecentProjects that's set to "use client", and also passing it as a prop in the Projects page. Am I on the right track? Thank you for your patience so far.
import { InferGetStaticPropsType } from "next";
import AnimatedText from "../ui/AnimatedText";
import Layout from "../ui/layout";
import FeaturedProjectTable from "../ui/project/FeaturedProjectTable";
import RecentProjects from "../ui/project/RecentProjects";
import { getStaticProps } from "../ui/project/fetchproject";
export default function Page({
projects,
}: InferGetStaticPropsType<typeof getStaticProps>) {
return (
<>
<main className="w-full mb-16 flex items-center justify-center overflow-clip dark:text-light">
<Layout className="px-0 xs:pt-10">
.............................................
<article className="py-16 dark:bg-[#121212]">
<div className="relative mx-32 flex flex-col justify-between lg:mx-14 md:mx-12 xs:mx-4">
<h2 className="my-8 block w-max border-b-4 border-solid border-purpledark font-ot text-4xl font-bold uppercase leading-snug tracking-wide dark:border-purple dark:text-light lg:text-3xl md:mx-auto md:w-max md:text-center md:text-2xl">
Recent Projects
</h2>
<article className="mt-20 grid w-full grid-cols-12 gap-16 xl:gap-8 lg:gap-0 lg:gap-y-8 md:gap-0 sm:gap-0 xs:gap-0 md:!gap-y-8">
<RecentProjects projects={projects}/>
<FeaturedProjectTable />
</article>
</div>
</article>
</Layout>
</main>
</>
);
};@Collared Plover Remember, you asked me to create a server component that contains getStaticProps and export it. I have done so, and I'm passing the prop in RecentProjects that's set to "use client", and also passing it as a prop in the Projects page. Am I on the right track? Thank you for your patience so far.
I never asked you to create a getStaticProps function. getStaticProps won't work since you're using app router
You've to move the content of getStaticProps to the use server function
@Anay-208 I never asked you to create a getStaticProps function. getStaticProps won't work since you're using app router
Collared PloverOP
import { InferGetStaticPropsType } from "next";
import AnimatedText from "../ui/AnimatedText";
import Layout from "../ui/layout";
import FeaturedProjectTable from "../ui/project/FeaturedProjectTable";
import RecentProjects from "../ui/project/RecentProjects";
import { getStaticProps } from "../ui/project/fetchproject";
async function getData() {
try {
// Fetch projects data from your API route
const { result, error } = await fetchProjects();
if (error || !result) {
// If there's an error or no result, throw an error to activate the error boundary
throw new Error("Failed to fetch data");
}
// Return the projects data as props
return {
props: {
projects: result, // Assuming `result` is an array of projects data
},
};
} catch (error) {
// Catch any errors and log them
console.error("Error fetching projects:", error);
// Return an empty object if there's an error
return {
props: {
projects: [],
},
};
}
}
export default function Page({
projects,
}: InferGetStaticPropsType<typeof getStaticProps>) {
return (
<>
<main className="w-full mb-16 flex items-center justify-center overflow-clip dark:text-light">
<Layout className="px-0 xs:pt-10">
.............................................
.............................">
<RecentProjects projects={projects}/>
<FeaturedProjectTable />
</article>
</div>
</article>
</Layout>
</main>
</>
);
}@Anay-208 You've to move the content of getStaticProps to the use server function
Collared PloverOP
Am i on the right track?
@Collared Plover Am i on the right track?
You are not even executing the function
export default function Page({
projects,
}: InferGetStaticPropsType<typeof getStaticProps>) {
const projects = (await getData()).props.projects
return (
<>
<main className="w-full mb-16 flex items-center justify-center overflow-clip dark:text-light">
<Layout className="px-0 xs:pt-10">
.............................................
.............................">
<RecentProjects projects={projects}/>
<FeaturedProjectTable />
</article>
</div>
</article>
</Layout>
</main>
</>
);
}Collared PloverOP
oh I should not return a prop?
this would be the right code
I'm expecting you to make required modifications
I request you to view the [nextjs docs](https://nextjs.org)
@Anay-208 I'm expecting you to make required modifications
Collared PloverOP
It worked😩 Thanks alot!, here's how i did it.
@Anay-208 I'm expecting you to make required modifications
Collared PloverOP
export async function getData() {
try {
// Fetch projects data from your API route
const { result, error } = await fetchProjects();
if (error || !result) {
// If there's an error or no result, throw an error to activate the error boundary
throw new Error("Failed to fetch data");
}
// Return the projects data as props
return result; // Assuming `result` is an array of projects data
} catch (error) {
// Catch any errors and log them
console.error("Error fetching projects:", error);
// Return an empty object if there's an error
return {
result: [],
};
}
}
export default async function Page({}: any) {
const projects = await getData();
return (
<>
<main className="w-full mb-16 flex items-center justify-center overflow-clip dark:text-light">
.......................................................
<article className="mt-20 grid w-full grid-cols-12 gap-16 xl:gap-8 lg:gap-0 lg:gap-y-8 md:gap-0 sm:gap-0 xs:gap-0 md:!gap-y-8">
<RecentProjects projects={projects} />
<FeaturedProjectTable />
</article>mark message as solution
mark my message as a solution
@Anay-208 Right click, apps>mark solution
Collared PloverOP
thanks minor error; Warning: Only plain objects can be passed to Client Components from Server Components. Objects with toJSON methods are not supported. Convert it manually to a simple value before passing it to props.
the error is self explainatory
@Anay-208 the error is self explainatory
Collared PloverOP
Thank you very much! 😊 Sir, may I come to you whenever I experience issues? This was the hardest issue I've encountered so far. I'm more than willing to start a new question and mark your solutions as the solution.
@Anay-208 the error is self explainatory
Collared PloverOP
Hello again,
I just wanted to express my gratitude for your assistance in resolving the issue I was facing. Your help was invaluable
, and I truly appreciate the time and effort you put into assisting me.
I completely understand if you prefer not to be contacted for future issues. Please know that I am grateful for your support and expertise on this matter.
Once again, thank you very much!
I just wanted to express my gratitude for your assistance in resolving the issue I was facing. Your help was invaluable
, and I truly appreciate the time and effort you put into assisting me.I completely understand if you prefer not to be contacted for future issues. Please know that I am grateful for your support and expertise on this matter.
Once again, thank you very much!
You can ping me anytime. you can express your gratitude at #kudos
No problem
@Anay-208 You can ping me anytime. you can express your gratitude at <#911305422307225682>
Collared PloverOP
Thank you for your kind support! I'll definitely keep that in mind. If I encounter any further issues, I'll be sure to reach out. Thanks again!