How can i fetch data in server components according to context value?
Answered
Deki posted this in #help-forum
DekiOP
there is "Connect wallet" button in my navbar. when users connect their wallet, my app should get their wallet address from context. then, my app should fetch data of that wallet address. as i know server components can't use context. so in this case there is any solution? i'm using next.js 14, app router, postgresql and prisma.
Answered by Plott Hound
no problem if you are happy with the answer and dont need more help please mark this as the answer, instructions to do so are in the first reply to you op
29 Replies
Plott Hound
Since context is client only and you’ll want to fetch on the server you have a few options.
- push the wallet address into the url eg url?wallet=4759374739
Then use search params to fetch the wallet id in a server component. Downside is you expose the wallet address to the url
- use a server action. You can call server actions from client components which would let you fetch data server side from a client side trigger
- push the wallet address into the url eg url?wallet=4759374739
Then use search params to fetch the wallet id in a server component. Downside is you expose the wallet address to the url
- use a server action. You can call server actions from client components which would let you fetch data server side from a client side trigger
@Plott Hound Since context is client only and you’ll want to fetch on the server you have a few options.
- push the wallet address into the url eg url?wallet=4759374739
Then use search params to fetch the wallet id in a server component. Downside is you expose the wallet address to the url
- use a server action. You can call server actions from client components which would let you fetch data server side from a client side trigger
DekiOP
@Plott Hound Thanks a lot.
@Plott Hound Since context is client only and you’ll want to fetch on the server you have a few options.
- push the wallet address into the url eg url?wallet=4759374739
Then use search params to fetch the wallet id in a server component. Downside is you expose the wallet address to the url
- use a server action. You can call server actions from client components which would let you fetch data server side from a client side trigger
DekiOP
Hi, in your second option, should i use useEffect hook in client component?
@Deki Hi, in your second option, should i use useEffect hook in client component?
Plott Hound
what would you need the useEffect for? without seeing any code i'd be guessing
@Plott Hound what would you need the useEffect for? without seeing any code i'd be guessing
DekiOP
so this is my UserInfoCard component. now i'm tracking user's wallet connection state using useEffect hook. how can i tackle this without using useEffect hook?
import { useEffect } from 'react'
import { useCurrentAccount } from '@mysten/dapp-kit'
export default function UserInfoCard() {
const [userInfo, setUserInfo] = useState({})
// get current connected wallet account
const account = useCurrentAccount()
const getUserInfo = async (address: string) => {
try {
const res = await fetch(/api/users/${address})
const data = await res.json()
setUserInfo(data)
} catch (error) {
console.log(error)
}
}
// when user connect his wallet, get his userInfo
useEffect(() => {
if (account) {
getUserInfo(account.address)
}
}, [account])
// display userInfo
return (...)
}Plott Hound
show me the /api/users/${address} route code
@Plott Hound show me the /api/users/${address} route code
DekiOP
// app/api/users/[address]/route.ts
// lib/data.ts
import { NextResponse} from 'next/server'
import { fetchUserInfoByAddress } from '@/lib/data'
export async function GET(
request: Request,
{ params }: { params: { address: string } }
) {
try {
const data = await fetchUserInfoByAddress(params.address)
if (!data) {
return NextResponse.json({ error: 'No user info.' }, { status: 400 })
}
return NextResponse.json(data)
} catch (error) {
return NextResponse.json({ error:${error}}, { status: 500 })
}
}// lib/data.ts
import prisma from '@/lib/prisma'
export async function fetchUserInfoByAddress(address: string) {
try {
const userInfo = await prisma.users.findUnique({
where: {
address,
},
})
return userInfo
} catch (error) {
console.error('Database Error:', error)
throw new Error('Failed to fetch the user info.')
}
}Plott Hound
thanks. are you using pages or app dir?
ignore that i can see the app folder
so instead of having the client side fetch and the route handler you can massively simplify this by making a server action that essentially just returns the result of lib/data.ts
personally if i was doing this i would take a different approach that is much more simple and follows nexts new data fetching patterns. when the user sets their wallet you just push it into the url like url?wallet=234239esdfhis234 then in the top parent of the route you can get the address with searchParams, then fetch the data with the same code in lib/data but passing the value of searchParams to it. then pass the wallet data down to the component that displays it
this method would make it really fast and avoid any client side fetching
the server action way would work but typicaly we shouldnt be using server actions for fetching
@Plott Hound thanks. are you using pages or app dir?
DekiOP
oh, it's wonderful.
Plott Hound
it would look something like this in you top level page component:
import prisma from "@/prisma/prisma";
export default async function FetchWalletPage({
searchParams,
} : {
searchParams?: {
address?: string;
};
}) {
let userInfo;
try {
userInfo = await prisma.users.findUnique({
where: {
address: searchParams?.address,
},
})
} catch (error) {
console.error('Database Error:', error)
throw new Error('Failed to fetch the user info.')
}
return (
<MyDisplayComponent userInfo={userInfo} />
)
}DekiOP
thanks for your kindness.
Plott Hound
i know this might seem unrelated but i think you will find this article very informing https://nextjs.org/learn/dashboard-app/adding-search-and-pagination
DekiOP
sorry to bother you. can i ask more?
Plott Hound
of course! ask away
DekiOP
in web apps, after user sign in, dashboard page will show. at that time, should i push user id to url to get it by params and fetch data in server component?
Plott Hound
show the line of code where the user gets redirected to the dashboard please
essentailly you want to add the address to the dashboard url then. so if you had eg redirect('dashboard') you would change it to redirect(
dashboard/${walletid}) or somethingassuming the user has already entered their wallet at that point
DekiOP
thanks. but my boss doesnt' want to show wallet address in url. in this case, would i fetch data in client component?
Plott Hound
yeah doing it in the client is fine. i'd recommend the SWR library to do the fetch: https://swr.vercel.app
as long as you dont need to access any secure api keys while doing so its fine
DekiOP
thank you so much
Plott Hound
no problem if you are happy with the answer and dont need more help please mark this as the answer, instructions to do so are in the first reply to you op
Answer