Next.js Discord

Discord Forum

How to Restructure Nested Client/Server Components due to Auth?

Answered
Crazy ant posted this in #help-forum
Open in Discord
Crazy antOP
I've been thinking straight for 2 days. Nobody on stackoverflow is answering, nobody else knows how to handle this and I'm so so desperate for help. I'd be no-joke forever grateful for an answer.

Overall, my application relies on a browser extension that allows users to sign data with their private keys, while revealing their public key as some sort of a "username".

The users are able to submit "products" and view them others products at any time. So I have a route, /products. This route is handled by the component ProductsPage, which is a server component that fetches products (this doesn't need authentication or any user specific data).

Now, each user could have "bought" the product. So, they may decide to connect the browser extension to my page and give me their public keys. If user gives me the public keys, I have to fetch user-specific information, such as how many units the user has bought. I need the users public key to do that, and I want to fetch this using a server component. I could easily do this client-side, but it would increase latency.

To understand whether the user connects the browser extension, I have a hook called "useKeys()" which returns the users public key if the user connects their account. This must be executed on the client side.

I don't know how to structure this. Basically, this is how I want it to look (with server/client indicated at the end of the component name):

<ProductsPageServer>  // /products, fetches products from the server, doesn't need any login
    <KeyListenerClient> // uses useKeys() hook to listen to authentication, must be client.
        <UserProductInteractionsFetcherServer> // must be server, accesses the data
            <Rest_Of_The_Stuff_No_Problem_Client />
        </UserProductInteractionsFetcherServer>
    </KeyListenerClient>
</ProductsPageServer>


I can fix the whole problem by making <UserProductInteractionsFetcherServer> a client component, but then data will be fetched client-side.
Answered by Crazy ant
I think I'll use this + Route handlers
View full answer

47 Replies

Golden-winged Warbler
Crazy antOP
Yep
Thrice, but I can't find a pattern that works. Thanks for the reply!
Golden-winged Warbler
Have you looked at Server Actions? (they are alpha from my understanding)
otherwise, you might be looking at a traditional API call
or maybe you just want a path or query param to your page?
Crazy antOP
I was actually using server actions before but I'm concerned that they are in Alpha. Looks like the best thing to do here is traditional API call, but this quote from the website really convinces me that there must be way I can't think of:

Although it's possible to fetch data in Client Components, we recommend fetching data in Server Components unless you have a specific reason for fetching data on the client.
Golden-winged Warbler
/products shows all, /products/[publickey] shows filtered
Crazy antOP
Hm yeah I can do that, but how would I know when the user gives me their public key? I need to listen to that in a client component so that I can redirect them to this page
@Crazy ant I was actually using server actions before but I'm concerned that they are in Alpha. Looks like the best thing to do here is traditional API call, but this quote from the website really convinces me that there must be way I can't think of: > Although it's possible to fetch data in Client Components, we recommend fetching data in Server Components unless you have a specific reason for fetching data on the client.
European sprat
that's for initial fetching but if you want to fetch data based on a user action (such as them adding their pubkey) you then have to either use a server action or an API fetch. in either case, the client would pass the pubkey to your server and you do the fetch on the server then return the results to the client
Golden-winged Warbler
if it's a public key, how do you know the person providing it is the original? Isn't it public by nature, isn't the extension mainly for keeping private keys away from you?
any of the chain explorers allows anyone to input a public key and see info about it, this doesn't sound much different
in other words, it doesn't seem like the extension needs to be in the mix here, but if you provide a button to buy a product, that will need the extension to do private key things on the client only
perhaps the extension is more of a convenience for the user?
@Golden-winged Warbler if it's a public key, how do you know the person providing it is the original? Isn't it public by nature, isn't the extension mainly for keeping private keys away from you?
Crazy antOP
What the user "bought" is public, but to buy something user needs to sign it with their private key. If they don't provide the original they can't get any data that isn't public. Yep it's very close to how Ethereum/Wallet connection is handled, but instead it's a specific key-signing application that's just a "hobby" project that I want to complete
Golden-winged Warbler
does it matter if this is a hobby project?
European sprat
that's a personal choice but they are currently experimental/unstable
@Golden-winged Warbler does it matter if this is a hobby project?
Crazy antOP
Nope, I'm doing this project to learn the new App components. I need the extension because, for example, there's a buy limit to some products. So if the user has exceeded their buy limit (stored in the database, on a document with their public key) then they are not allowed to buy it
@Golden-winged Warbler `/products` shows all, `/products/[publickey]` shows filtered
Crazy antOP
To rephrase my question, I basically need a "reactive fetch" that is done server-side. If the user, connects to my page, then I somehow need to fetch new information (which I want to do on the server) and update the fetched data
Golden-winged Warbler
Server Actions are forward looking, probably worth learning them along the way
Crazy antOP
I'm really concerned that they are experimental, but since this project won't be actually used I think I'll use them here
Thanks for all the replies, I've been thinking what to do here for 2 days straight!!!
European sprat
FYI server actions are just POST requests under the hood
i think server actions are also supposed to be used more for mutating data not just fetching data
@European sprat FYI server actions are just POST requests under the hood
Golden-winged Warbler
except you get html back and that gets inserted where appropriate?
European sprat
no it doesn't respond with HTML
@European sprat i think server actions are also supposed to be used more for mutating data not just fetching data
Golden-winged Warbler
right, which is why query or path params make sense here
European sprat
i really think the OP should be making a fetch to a route handler API endpoint
client passes pubkey and whatever else you need to the route handler --> route handler queries the db and does whatever else it needs on the server --> route handler responds with data
@European sprat i really think the OP should be making a fetch to a route handler API endpoint
Crazy antOP
That's what I've been doing but if I somehow move the fetch functionality to the server latency will be reduced by a lot
Oh wait
European sprat
the route handler endpoint IS on the server
Crazy antOP
right, thanks so much I'll try this and let you know!
Ok nevermind, sorry I confused route handlers with something else, they are basically like the old /api right? That's what I've been trying to avoid
Golden-winged Warbler
can the API method cache results (magically) like the param method, if we consider a situation where multiple users are wanting to look at the same publickey based view?
@Crazy ant Ok nevermind, sorry I confused route handlers with something else, they are basically like the old /api right? That's what I've been trying to avoid
Crazy antOP
But now that I look at it nothing else really makes sense, since I somehow need to listen to account changes
Golden-winged Warbler
what if you listen to account changes and then push a path onto the router?
@European sprat why are you trying to avoid it?
Crazy antOP
I was trying to avoid round-trip and back, because after the user connects I'll have to fetch from the server. Instead I was looking for a way to fetch data from the server... nevermind now that I write it out it makes no sense at all, it's like asking for user data without knowing who the user is
Golden-winged Warbler
these rely on the path to container the public key, which should also mean, that if 2 users (or 1 user on different devices) will share the rendered results. That is, the second request would not need to actually query the chain, it already knows the results for this public key. You could get cleaver and set the nextjs cache time to match the block time for a chain, since nothing should change in between blocks
Though I suppose most chains are opperating with pretty short block times these days, especially if you account L2
Crazy antOP
Took me a while to understand how they work but I get it know this is so useful
Crazy antOP
I think I'll use this + Route handlers
Answer
Crazy antOP
It really solves everything, thanks so much!!