Fetch own API from client with async
Unanswered
Mini Rex posted this in #help-forum
Mini RexOP
I have been sitting for ages trying to get the data from my own API '/api/.../getInventory' but to no avail. I have been trying client sided with async but it says its not supported. I have tried fetching and in a .then returned HTML data to the user. but its not working would be nice if somebody knew a solution so i can get out of this rabbithole
"use client"
import axios from "axios";
import { useEffect, useState } from "react";
import { Sidebar } from "../../components/objects/sidebar";
import { session } from "@/app/api/data/session";
import { NextResponse } from "next/server";
export default async function Inventory() {
const inventoryData = await fetch('/api/.../getInventory')
return (
<div className="flex h-full w-full flex-row">
<Sidebar/>
<div className="w-full h-full bg-[#111216] p-[15px]">
<h1 className="w-full mb-[3px] font-semibold tracking-wide text-[#909090] uppercase">Inventory</h1>
<hr className="border-[#303030]"></hr>
{inventoryData && (
inventoryData.map((item: any) => {
return(item)
})
)}
</div>
</div>
)
}55 Replies
Giant panda
Client components can't be async. You have to either fetch the data in a server component and pass data down to the component via props or use classic client-side fetching libraries such as SWR or react-query.
And if you fetch data in server components, don't use the route handler and just query data directly.
Here's an example how I query my database and pass on data down to the client component: https://github.com/JetBrains/webstorm-rsc-webinar/blob/b1f1579858a1e9979a9df6422dbdb5e4deab9795/app/page.tsx#L60-L97
@Giant panda And if you fetch data in server components, don't use the route handler and just query data directly.
Mini RexOP
Is there a way to get rid of "use client" then use a normal fetch get the data and then return the html and data to the client? Im coming from Node JS Express so still an unknown territory
Giant panda
As long as you don't need interactivity or client-side APIs you can remove the
use client directive and have a server component(Same applies though, don't ever fetch own route handlers in server-side code)
Mini RexOP
Yes the code provided is the page.tsx file which is in a directory. And i just need to use a normal fetch to fetch some data from an endpoint so i can display the data which was recieved
Giant panda
If you browse the repository I just linked, it only has like two relevant files (
page.tsx and components.client.tsx) that you could investigate to see what approaches are available.Mini RexOP
Im trying to make it fetch when the page is loaded
In short:
async function Component() {
const data = await getDataFromDatabase()
return <div>{data.foo}</div>
}Mini RexOP
I'm not sure i entirely understand your example.
"use client"
import axios from "axios";
import { useEffect, useState } from "react";
import { Sidebar } from "../../components/objects/sidebar";
import { session } from "@/app/api/data/session";
import { NextResponse } from "next/server";
export default function Inventory() {
return (
<div className="flex h-full w-full flex-row">
<Sidebar/>
<div className="w-full h-full bg-[#111216] p-[15px]">
<h1 className="w-full mb-[3px] font-semibold tracking-wide text-[#909090] uppercase">Inventory</h1>
<hr className="border-[#303030]"></hr>
</div>
</div>
)
}In this file?
Giant panda
Remove the client directive and query your data in that component where it's needed
export default async function Inventory() {
const data = await getFromDb()
return (
<div className="flex h-full w-full flex-row">
<Sidebar/>
<div className="w-full h-full bg-[#111216] p-[15px]">
<h1 className="w-full mb-[3px] font-semibold tracking-wide text-[#909090] uppercase">Inventory</h1>
<hr className="border-[#303030]"></hr>
{data.map(...)}
</div>
</div>
)
}Mini RexOP
when you say await getFromDb do i need to import a component which is stored in another directory?
Giant panda
I am assuming you have a function that obtains items from the inventory
That should be the function you call directly
Mini RexOP
So it can be in the same file after removing "use client"?
Giant panda
Ah that's what you meant.
Yeah, it can even be directly copy pasted into the component if it's only a few lines and not reused
There is no real restriction how you structure your functions on the server.
I typically just query directly in the component unless it's more than a few LoC
Mini RexOP
I havent tested it but something like this? the map thing is causing all kinds of errors but just making sure.
import axios from "axios";
import { useEffect, useState } from "react"; // Import useEffect and useState
import { Sidebar } from "../../components/objects/sidebar";
import { session } from "@/app/api/data/session";
import { NextResponse } from "next/server";
async function getInventoryData() {
axios.get('/api/.../getInventory').then((response) => {
return response.data;
})
.catch((error) => {
console.error("Error fetching inventory data:", error);
});
}
export default async function Inventory() {
const inventoryData = await getInventoryData()
return (
<div className="flex h-full w-full flex-row">
<Sidebar/>
<div className="w-full h-full bg-[#111216] p-[15px]">
<h1 className="w-full mb-[3px] font-semibold tracking-wide text-[#909090] uppercase">Inventory</h1>
<hr className="border-[#303030]"></hr>
{inventoryData && (
inventoryData.map((item: any) => {
return(item)
})
)}
</div>
</div>
)
}Giant panda
No you are ignoring what I said earlier. Do not fetch your own endpoint.
Mini RexOP
Ohh sorry
Giant panda
The code you have in your
/api/.../getInventory route handler can be fully copy pasted into getInventoryDataAnd on a different note, you should check out this for the future: https://www.adios-axios.com/
Mini RexOP
I just don't understand how this all holds together. You're telling me i shouldnt fetch the endpoint i need to get data from... I'm using a route handler in my project. Looks like this:
This is my structure
Giant panda
export function GET() {
// COPY THIS
}
// ...
// in your component file
async function getInventoryData() {
// IN HERE
}Route handlers are only meant for fetching from client-side component (which is barely necessary nowadays) and for 3rd parties
Mini RexOP
Wait let me catch up here. You are aware that i'm in the 'page.tsx' file of inventory meaning thats the file that gets displayed. Do you want me to make a new file which has the export function GET() {} because i have just that in my other file which is the endpoint im trying to reach. I have fetched data from it before and i know its returning what its supposed to but i cant use the in the html that im sending to the client. Sorry if i'm a little hard to work with
Giant panda
No, I am saying you don't need route handlers or endpoint at all.
Pages and server components are run on the server and allow direct server code.
Mini RexOP
But im making endpoints so i can use them other places aswell
Giant panda
So you can directly query databases, files etc. and render them. No need for a fetch call to yourself.
@Mini Rex But im making endpoints so i can use them other places aswell
Giant panda
Then make them reusable functions.
And call these functions in all pages where you need the data.
Mini RexOP
I'm sorry but i understand but i dont understand. It would just be really convenient to use endpoint because thats what im used to :/
Giant panda
But that's not how it works anymore and it will cause problems.
Querying data directly without the needless step to fetch endpoints is much more direct and easier anyways
Mini RexOP
Ugh but i have already set up the endpoint to work is it easy to move over?
Giant panda
Rename it from
GET to something sensible, move the function to a different file and call it directlyIt's really not that much
Giant panda
Indeed. It just needs to be simplified since there are no responses afterwards.
Just returning results directly or calling things like notFound() etc
Mini RexOP
Okay sure i have renamed it
So now you want me to link it to the page file?
:
@Giant panda Rename it from `GET` to something sensible, move the function to a different file and call it directly
Mini RexOP
When console logging it, it returns "[AsyncFunction: get...Inventory]"
Hokkaido
@Giant panda So I should just query the database in a server component rather than use route?
@Mini Rex When console logging it, it returns "[AsyncFunction: get...Inventory]"
Giant panda
It's an async function and I guess you didn't await the response.