Hooks and Server Components

Hello! As I’m developing my current project on RW7 with gql and the current infrastructure, I was amazed to see the Bighorn news and the switch to RSC. In preparation, I’m trying to make sure my app logic easily translates to Bighorn once it’s production ready and I have minimal changes to make.

A few things stood out to me when it comes to thinking in server components and Redwood.

  1. I am assuming Layouts will be server components, just by necessity of how the data flows and rules around server/client
  2. How will dbAuth work with RSC? Since we utilize the useAuth hook, I am assuming it has to be done in a client component. If I used some kind of permission/role check at the page level it would turn a page into a client component and everything below its tree wouldn’t be able to be server side, no?
  3. How will React Context interact with this? Since we use hooks, I am assuming again that you can’t just wrap a provider in App.tsx because layouts and pages perhaps need to be server components. So lower in the tree, which can invite duplication (Currently I just wrap my context providers around the children in App.tsx).

I am thinking that my app will look something like this in its structure:

Layout (server) → Pages (server) → Components (either server or client, utilizing the trick Dan mentioned here by importing at the page level)

Realistically, this means layouts can fetch data themselves or with a server cell, same for Pages. However, any use of context or auth would have to be handled inside specific client components. Am I understanding this correct?

  1. Yes, Layouts will be server components unless you do “use client” at the top.

  2. We’re rewriting much of the auth implementation to prepare for RSCs. It’ll be cookie based and have full role support on the server too

  3. So <App>, and the contexts in there render on the client. That means that any client components you have on your pages can use those clients.

Your flow there looks correct. And like you say - we have server cells for doing data fetching in server components like your layouts. As I said in 2. we’ll make auth work in server components too. So in client components you’d use useAuth(). For server components we haven’t really decided yet. We could do useAuth() there as well. It wouldn’t really be a hook, but it’d return the same things, like isAuthenticated, hasRole() etc. Or we could name it getAuth() or getServerAuth() just to make it extra clear it’s not actually a hook. What do you think? What would you prefer?

1 Like

Thanks for your response Tobbe! It’s always a pleasure to read your insights.

I guess I just wanted reassurance on the auth part that it won’t break and we’ll be able to use it in server components. I plan on switching to Bighorn once it’s further in the development cycle, but I am preparing my current app with the new paradigm shift in mind. I didn’t want to write all this authorization logic to have it stripped once I swap over so knowing that puts me at ease, haha.

I think the downside of changing the server based auth function would mean that developers like me who are implementing it right now would have to rename in their codebase. The upside of course is that there is a clear distinction. I think long term it shouldn’t be called useAuth, but rather getServerAuth to clearly distinguish it from the client side and since it’s not a hook the get prefix makes sense. I like it.

On #2 I must’ve been confused, I thought the order of things was App.tsx > Layouts > children, but if I’m understanding you correctly the App.tsx wraps around pages (or more accurately around routes)? I do something like this:

import AllContextProviders from 'src/providers/context/index'

const App = () => (
...
          <AllContextProviders>
            <Routes />
          </AllContextProviders>
...
)

So that should still work and allow me to use context hooks in pages and components–even if they are server components?

1 Like

Yes, that’d work

No. You’d have to use client components inside your pages to use the contexts provided by <AllContextProviders>

1 Like