⏳ Chapters
- Using Our Layout
- Inspecting Our Layout
So today let's introduce Layouts by moving our authentication shell into a Layout file and using it for both our login and register pages.
So the first thing that we're going to want to do is create a file for our Layout. Now you could create your Layouts inside of your components, but what I like to do in this case
is to create a separate folder altogether called Layouts with my Layouts inside of it directly off of Inertia. So I'm going to create a new file here. We'll call this folder
Layouts and then we'll do AuthLayout.view for the actual Layout file. For right now all that we need is a template. Go ahead and wrap everything
in a div and then we'll have a header with a nav inside of it. And then on this nav we'll do flex items center justify between
with a padding of 6 and a lgpx of 8. Inside of it we'll do an extra div class flex lg flex 1 with
a link component inside of it with an href pointing to the home page. And on this we'll have a class of negative margin 1.5
and a padding of 1.5 as well. Then we'll end that link. Inside of here we'll do a span class sr only and put out a label
for our application of PlotMyCourse. And then we'll grab an svg here in a minute to plop in as our actual icon. So I'll just
put a comment there for right now. And then beside the div inside of our navigation we'll do another div with a class flex flex 1
justify end and a gap of 4. Inside of here we'll put another link component with an href pointing to /register and
a class of text small font semi bold leading 6 and text slate 900. Go ahead and end
that link component. Keeps wanting to do divs for that. I don't know why. And write out register inside of there. We can go ahead and give that link a copy and a paste and switch
the anchor to login instead of register and the text to login instead of register as well. Cool. So we have ourselves a little header here for our
auth layout. Then we need the actual page contents. So let's do another div class and let's apply a padding of 6 there. And then lg will do a padding
of 8. Then we'll do our actual page contents. However from our login page we want to take this div and now move it out to our layout so we can get rid of
it inside of our login page. Just kind of cut it out there. Go ahead and give that a save. Jump back into our auth layout and paste it in. Inside of this div we'll just do a
slot so that any contents that we place inside of our actual page components gets rendered out in this slot right here. Oh! Forgot
about our SVG icon. Let's go ahead and grab that real quick. So let's open up our browser. This is just coming from Lucid. So lucid with an e dot dev. It might
be pronounced Lucide. I'm not quite sure. Go into view all icons and we're just using the routes icon right here. So we can go ahead and give that a click.
Go down to the download SVG. Click on a caret and copy the SVG. Cool. We can close that out for now and hide our browser. Go to where we have our SVG placeholder
and just paste it in. Give it a save so that it formats. Scroll back over to the left. We do want to switch up the class a little bit so we'll do a height of 8
and a width of auto on it and we can give that a save. Alright so your first inclination for using this layout may be to jump into your pages, go into the
template and then try to use your auth layout like so. Wrapping all of your page contents inside of that auth layout and then since that's not inside of our components
directory we would need to import it to register it. So auth layout from we could do tilde slash layouts slash auth
layout dot view. Give that a save and while this will physically work we can jump back into our browser and we'll see everything kind of go back. Oh, one blank less refresh. There we go.
We can see everything kind of go back to how we had it for the page contents and then we also have our header right up here. The downside here is as we click from page to page, now
we don't have it on our register page but assume that we did, it would re-render all of the layouts contents for each link that it goes to. Whereas it would be preferable
if it shared and doesn't actually try to re-render everything as that could result in a flash as it re-renders. So what we want is to
use the layout outside of our page level in between the inertia component and our page component. So we want to elevate this up to our application
level instead of using it inside of our individual pages. So let's go ahead and undo what we did here inside of our logout page. Go ahead and just remove the registration
of our auth layout and remove its usage altogether. And let's jump into our app.ts file. If you remember inside of this file we have a resolve method that's
in charge of resolving out each of our page components as we attempt to render them. Now we can make use of that by intercepting and grabbing a reference to that
component. So for example we could do const page equals resolve component and then down at the bottom of this method return that page. And now we have the actual page
component that we can work with and use to our advantage to add a layout into it. The app component from inertia actually accepts and will read
from a layout property on our page components and then wrap our page in that layout that we provide. For example, if we go ahead
and import our auth layout here. So import auth layout from we'll do ~/layouts/auth-layout.view
there. We have reference to our page so we can do page.default.layout to attach a layout property onto that default export
equals auth layout. Okay so one more thing here. Default does have a red squiggly on it. It is because resolve page component is a promise
so we need to await it and then switch our resolve function to async as well which gets everything being back to happy. And now we need to
inform our server side app about this as well so that we don't get a hydration mismatch. So let's jump into our SSR app and do the exact same thing. So we'll import our
auth layout from ~/layouts/auth-layout and then here too we are using our resolve method to resolve out all of our
pages rather than just one and then finding the applicable page and returning it back. So rather than returning back just like we did within our app we want to save
this into a variable. Now we already have page being provided into this render function up here so what we want to do instead is maybe resolve
page or something of the sort and then just like we did within our app we can do resolve page.default.layout
equals and then apply our auth layout to that property. We'll want to return back that resolve page as well. Alright, we can give that a save.
Now if we jump back into our browser you'll see that everything looks the exact same here for our login page. We can give it a refresh for sanity's sake and it looks the same. Now our register page
never had the layout applied to it but if we click over to it now it does because it's being picked up from our actual application shell now and being applied
by the inertia app component that resides between the inertia component and our page component. So if we inspect, jump into the view dev tools
we can see the root of our application, the inertia component, and then the auth layout now wrapping our actual page component here and this
layout is now being provided by default. We don't need to do anything inside of our actual page to add it in. It will just automatically take hold because
we've added it at the application level.
We'll learn how to create a layout component and apply it to all our pages, the Inertia way.
- Using Our Layout
- Inspecting Our Layout
If we do something like this in react
```
resolve: async (name) => {
const page = await resolvePageComponent(`../pages/${name}.tsx`, import.meta.glob('../pages/**/*.tsx'))
page.default.layout = page.default.layout || (page => <MainLayout>{page}</MainLayout>)
return page
}
```
We get typescript errors that page is of type unknown
, what would be the proper typing for page?
Hi cubicalprayer712!
Vladimir kindly left steps on getting this setup in React in the next lesson's comments if you'd like more details, but something like the below should satisfy the needed typing.
const page = await resolvePageComponent( `../pages/${name}.tsx`, import.meta.glob('../pages/**/*.tsx'), ) as { default: ComponentType & { layout?: (page: ReactElement) => ReactElement } } page.default.layout = page.default.layout
Copied!