Intro to Inertia React0:00
Let's take a look at how we can use React and Laravel together using Inertia.js. There's already an entire series on using Inertia with Vue, so be sure to check that out if you want to go deeper on all the features Inertia has to offer. In this video, we'll just do a quick overview of some of Inertia's features with React on the frontend. As always, we'll build the obligatory blog example. So if you're not familiar with Inertia, their tagline is JavaScript apps the monolith way. So it's safe to have all the benefits of a single-page app without all the confusing parts.
So it's safe to have all the benefits of a single-page app without all the confusing parts. I like to think of it as a traditional server-rendered Laravel app, but with all of your Blade views replaced with JavaScript, in this case React components. So Laravel Breeze has official scaffolding for Inertia React, so if you need Auth already set up, be sure to check it out here. You can find it on the Laravel documentation page. So this will install Inertia with React, as well as all of the Auth scaffolding. Also check out the example app that Inertia has, it's called PingCRM and demonstrates all of the features of Inertia.
Also check out the example app that Inertia has, it's called PingCRM and demonstrates all of the features of Inertia. If you go down here to demo app, you can check it out at this link. So it's a basic CRUD app that shows all of the features of Inertia. We have different models here, contacts for example, and we can perform CRUD actions on all of these models here. So the code is Inertia with view, but there is a forked version with React, which you can take a look at here. But for our demo here, we'll create it from scratch. So let's get started with installation.
Server-Side Setup1:25
But for our demo here, we'll create it from scratch. So let's get started with installation. There is a server-side portion as well as a client-side portion, so let's start with server-side setup. So I do have a blank Laravel app here set up already. All I've done is set up the database. Let's get started. Let's make sure to composer require the Inertia Laravel scaffolding. Let's go ahead and run that here. Okay, next, you have to set up the root template.
Let's go ahead and run that here. Okay, next, you have to set up the root template. So this should be app.blade.php, as it says right here. So let's go ahead and add this. So let's go to our Laravel project. Let's go to Resources, Views, and we'll add one called app.blade.php. Paste that in. Okay. As you can see, there are some directives here which allow Inertia to run correctly. What's next?
As you can see, there are some directives here which allow Inertia to run correctly. What's next? Next, we have to set up the middleware here. So php artisan, Inertia, middleware, and we have to add that in the web middleware group within app/Http/Kernel.php, so let's add that. Let's grab this. Let's go to app/Http/Kernel.php, and let's put it within the web group right here. Okay. Let's save that. What's next?
Client-Side Setup2:46
Let's save that. What's next? Next is creating responses, which we'll do after we set up the client. So that's it for the server-side setup. Let's go to the client-side setup here. And we are using React, so I have that selected here. So first, we have to install the adapters. So let's grab that. Paste that in. Okay, that's done.
Paste that in. Okay, that's done. And it's not in the documentation, but you actually have to install React manually as well. So let's go ahead and do that. So npm install. We need react and react-dom. Okay, that's done. Next we initialize the app. So we can add this code within our app.js.
Next we initialize the app. So we can add this code within our app.js. So let's grab this. Let's copy that. Let's go to our resources/js/app.js file, and let's paste that code here. You can keep the bootstrap in if you like. This has some setup for other things like lodash. So I'll just keep it in there, and I'll paste our code underneath. Okay, save that. What's next?
Okay, save that. What's next? Next we have a progress indicator, which is optional. So as we make requests, it has this little progress bar, which shows up in your application. Again, this is optional, but we'll install it anyways. So let's grab this. Let's paste that in. We can import it like this, and then put it in our app.js here. And let's put this underneath here. Okay, let's save that.
And let's put this underneath here. Okay, let's save that. What's next? Next is code splitting. And I believe this is already set up if we're using Laravel Mix. You can see down here, it says if you're using Mix, it's already configured. So we can skip that. And now it says to add this import file instead of require within our setup. Let's paste that in here and replace the require call. Okay, get rid of this.
Let's paste that in here and replace the require call. Okay, get rid of this. Let me just delete it actually. And what's next? I think that's it. You can do cache busting as well. But since we're using Mix, you can add a version method to do that for us. And I think there's one more thing we have to do here that's not documented, at least not on this page. But within our webpack.mix.js file, we have to say .react somewhere here.
not on this page. But within our webpack.mix.js file, so we have to say mix.react somewhere here. So our React files are compiled correctly. Save that. And let me run npm run dev here. And it installed some extra dependencies here. So let me run that again. Okay, and we do get an error. That's because it can't find the pages directory.
Routing Pages and Props5:39
Okay, and we do get an error. That's because it can't find the pages directory. So if you go back here to our app.js, you'll see it's looking for that pages folder here. So let's go ahead and create that within resources/js. Let's create a pages folder here. And we'll add one called index.js or index.jsx. So let's make this a React functional component. This is fine for now. But now we have to specify a route for it.
This is fine for now. But now we have to specify a route for it. And with Inertia, you can just make use of Laravel's router. So let's go to routes/web.php. Let's replace this route with Inertia instead. So instead of using return view('welcome'), we can use return Inertia::render(), give it the page name. So in this case, index. You can add folders too if you like. And if you want to pass any data, you'll pass it the same way using an array here.
You can add folders too if you like. And if you want to pass any data, you'll pass it the same way using an array here. So for now, let's just hard code foo bar. Okay. Let's make sure to import Inertia here. Okay. Make sure I add my semicolon. Let's save that. And I'm going to run my watcher here. So I don't have to keep running npm run dev on each change.
And I'm going to run my watcher here. So I don't have to keep running npm run dev on each change. So let's say npm run watch. Okay, now my watcher is running. Let's check this app out in the browser, and hopefully it renders our index React component. So within here, let's refresh this, and it looks like it's working. So again, if you wanted to add pages, just add them as React components, add a new route for them, and you should be good to go. So let's add a few more here. And of course, you can use controllers if you like here.
So let's add a few more here. And of course, you can use controllers if you like here. But I'm just making use of the closure syntax. So let's add three more. One for, say, about, and I won't pass in any data here. Let's just make a page called about. Okay. Actually, let me just duplicate that one. Let's make one for contact. Okay.
Let's make one for Contact. Okay. And we'll make one for a Posts page for our blog. So this will be /posts. And we'll name it posts. Let's go ahead and make those React components. So basically the same as this. Let's duplicate a few times, contact, about, and posts. And let me just update this one here. And I'll do the other two behind the scenes.
And let me just update this one here. And I'll do the other two behind the scenes. Don't forget to change the function name as well. Okay. So I updated those components. Let's make sure it works in our app. So we have our main one here. We have /about, we have /contact, and we have /posts. Okay. Cool.
Creating Shared Layouts8:38
Okay. Cool. So I'm not going to add styles here, but you can import CSS any way you like, whether it's using traditional global CSS, CSS modules, or any CSS framework like Bootstrap or Tailwind. Next let's take a look at creating layouts. So usually you want your pages extending from a layout, whether it's one master layout or multiple layouts. So we'll just take a look at one example here where we're just making use of one layout, pretty much as you expect. Just make a new component, which is a layout.
pretty much as you expect. Just make a new component, which is a layout. And then within your pages, you can wrap your component with that new layout. So let's create a layouts folder. So within here, let's say new file, layouts/guest.jsx. And let's make a React functional component Guest. Let's grab the layout from the example here. So as you can see, we're also making use of the link tag to link to our pages. So just like router link in React Router or the link component within Next.js. So let me paste this in and we have to grab the children from the props here.
So just like routerLink in React Router or the Link component within Next.js. So let me paste this in and we have to grab the children from the props here. So let me just destructure the children. Okay. So now we have this layout and to make use of it, we can go to our components and wrap it with this layout. So for example, for our index, we can wrap this within Guest. So let me just reformat this. Let's wrap it with a Guest component. Let's import that.
Let's wrap it with a guest component. Let's import that. Okay. Make sure to close it out here. And hopefully that should work. Save that. Let's check out our index page. So back to our index. And that is not rendering. I think I forgot to import the Link component.
And that is not rendering. I think I forgot to import the Link component. So let's import this. Should be this one here. Okay. There it is. Let's save that. Try again. And there is our layout rendering here. So we have to do the same for the other components as well.
And there is our layout rendering here. So we have to do the same for the other components as well. There's also options for specifying a default layout if you scroll down, but I'll just stick to this for now. So I'll just add the guest layout to the other components the same way we did it here. So I added them to each component. Let's take a look at the browser and everything is working now. Cool. And I think I forgot the posts page on our layout. So let's make sure to add that.
Building Posts CRUD10:54
And I think I forgot the posts page on our layout. So let's make sure to add that. Let's add one more link here. This should go to /posts and it's called posts. Okay. There it is. Now let's go ahead and try to grab a list of posts here. So again, we are within a Laravel app, so we can just make use of it as we usually would. So let me stop this for now. Let's go ahead and make a new model for a Post.
So let me stop this for now. Let's go ahead and make a new model for a Post. So php artisan make:model Post and -a for everything else. Let's run our watcher again. And let's go into our migration. So create posts table and let's add some columns here for a Post. So I'm just going to paste it in. We have a title and a body. Usually you'd have a user_id here, which would specify the author of the Post. But to keep it simple, I just have a title and a body.
Usually you'd have a userId here, which would specify the author of the post. But to keep it simple, I just have a title and a body. Okay. Let's go to our PostSeeder. So PostSeeder. Sorry, I meant PostFactory. So PostFactory. And let's define how we want this factory to create a Post. So again, I'm just going to paste it in. We want a title, which we'll use Faker to generate four random words.
So again, I'm just going to paste it in. We want a title, which we'll use Faker to generate four random words. And for body, we'll make use of Faker to generate four sentences. So let's save that. Let's go to our seeder, so DatabaseSeeder. And let's uncomment this. We'll make use of our PostFactory and we'll create 10 posts. Let's save this. Actually, let me go to my Post model as well, right here. And let's set guarded to an empty array.
Actually, let me go to my Post model as well, right here. And let's set guarded to an empty array. Okay. And if I did everything correctly, if I stop this, run php artisan migrate:fresh --seed. I have an alias for that, MFS. That looks like it worked. Let's check our database here. Let me just refresh this posts. And there are our 10 posts. Okay.
And there are our 10 posts. Okay. Let me run my watcher here. So to grab data, we would just do it the traditional way. So within our routes/web.php, we can just pass in data like this. Oh yeah, I forgot to show you how to do that within here, but we'll do it here anyways. So the name would be posts and this would be passed in as a prop to this component here. And for that, we just want to grab all of the posts. So Post::all(). Okay.
So post all. Okay. Make sure to import post. Let's save this. And now within our Posts React component, we can make use of that. So let's go to posts.jsx. There should be a new prop called posts that's being passed in here. So we can grab it using props or we can destructure it, which we'll do here called posts. And within here, we can just map over them and show them here. So I'll make an unordered list here.
And within here, we can just map over them and show them here. So I'll make an unordered list here. And here's where we can map through them. So we'll say posts.map takes in a single post. And within here, we can put a list item here. Let's just specify the post.title, close that out. And I believe I need a key for each item as well. So we'll say key equals post.id. Okay, hopefully I did that right.
So we'll say key equals post.id. Okay, hopefully I did that right. Let's save that. Let's go to our page here. Let's refresh. And we are getting the data back from our backend. So again, anything you specify within here will get passed as a prop to our react component. And then we can make use of it however we like. So in this case, we just displayed them here. So I'm also passing this variable to our index.
So in this case, we just displayed them here. So I'm also passing this variable to our index. So let's add that as well. In this case, we'll just do props. And we can just say props.foo. Okay. Save that. Go to our index. And there's bar. Let's make a page for the single post.
And there's bar. Let's make a page for the single post. So it'll be post/. In this case, I'll just use the ID. And then we'll link to it here. So let's create that new React component. I'll just duplicate one of these. This one. Let's duplicate it. Let's say post.jsx.
Let's duplicate it. Let's say post.jsx. Let's rename this post. And within here, let's add the post.title and the body. So I'll put it within the h3. This will be post.title. And then we'll do one for the body. post.body. Okay. Let's make sure to destructure that from the props.
Okay. Let's make sure to destructure that from the props. Let's save that. Let's go back to our routes file. Let's make a new route for post. Duplicate this one. It's posts/{post} like this. It should take in the post here. We'll use route model binding here. Let's make sure to import that.
We'll use route model binding here. Let's make sure to import that. It's already imported. And within here, we can render the post component and we can pass in a single post here. So post is post. Okay. Hopefully, I did that correctly. Let's save that. Let's go back here. Let's try posts/1.
Let's go back here. Let's try posts/1. And that is working correctly. Let's make sure we can link to this page from within here. So we can replace our posts.jsx. We can make this a link here. So we'll say link. Make sure to import that. href equals and it should be /posts/{postId}. Make sure to close out that link here.
href equals and it should be slash posts slash postID. Make sure to close out that link here. And hopefully that should work. Save that. Refresh. They are links now. And it is working. Cool. Okay. Now let's take a look at how we can create posts.
Submitting Forms with useForm17:06
Okay. Now let's take a look at how we can create posts. So I've gone ahead and added some quick scaffolding for a form to create posts. Again, I apologize for not styling it, but you can see the code here. So we have state for our title and body using useState. We have a createPost method after the form is submitted. Right now it's only alerting createPost. And we have our form down here. We have our two inputs that have two-way data binding. So as the user types, the state is updated.
We have our two inputs that have two-way data binding. So as the user types, the state is updated. So we have one for our title and one for our body here. So as we submit the form, it's calling createPost. And all that's doing is alerting createPost here. Cool. So Inertia actually comes with a forms hook or a forms helper, very similar to the form libraries like Formic. So you can see we use the useForm hook, which gives us some useful things like the isLoadingState. In this case, it's called processing.
So you can see we use the useForm hook, which gives us some useful things like the isLoadingState. In this case, it's called processing. The errors, if there was any. And the actual data that gets updated as the user updates the state. So let's go ahead and make use of this instead of useState. And then we'll update our form code as well. So we no longer need useState. Let's paste this in. Let's replace it with title and body. So we just need title and body here.
Let's replace it with title and body. So we just need title and body here. By default, they are empty strings. So post is a method that we can call as we're creating a Post. So in this case, we want to post to the endpoint of /create. So we can say post /create. And we'll add that route in a second. Let's get rid of this now. And we have to update a few things in our form code. For example, the value is now going to be data.title.
And we have to update a few things in our form code. For example, the value is now going to be data.title. Let's update this as well, data.body. And for the onChange, we have to make use of setData instead of setTitle. So it's basically the same thing, but more of a generic setter. So let's grab that from here. Right here, let's grab this one. Let's paste that in. So now we're setting the data for the title field. And same for this one.
So now we're setting the data for the title field. And same for this one. By its body. Okay. Let's save that. Now let's create the endpoint for /create. We're posting to that endpoint here. So back to our routes/web.php, let's create a new endpoint for actually creating the Post. It's going to be a POST request to /create. And for now, let's just dd($request->all()).
It's going to be a POST request to slashCreate. And for now, let's just dd(request()->all()). Actually we have to import that Request, Request, make sure to import Request. Should be this one. And let's import that here, or dd(request()->all()) I mean. request()->all(), okay. So let's save that. Let's go back to our form. Let's refresh. And we have an error.
Let's refresh. And we have an error. useForm is not defined, forgot to import it back here. useForm, make sure to import that from Inertia. Should be this one. And we no longer need useDate here. Okay. Save that. And let's try again. Refresh.
And let's try again. Refresh. Okay. And now let's add some data in here. Title goes here. Body here. Let's go ahead and submit the form. And it looks like we do get that data on the backend. Now let's actually create the Post. So back here in our routes/web.php, let's create that Post here.
Now let's actually create the Post. So back here in our routes/web.php, let's create that Post here. So we can say post, create, and we have our title and body, okay, it's coming from the request. We'll do validation in a second. So the request title. And this is body. Okay. And usually after this, you would do a redirect. And within Inertia, you can do the same thing.
And usually after this, you would do a redirect. And within Inertia, you can do the same thing. So return, redirect. Let's go back to the posts page. And let's also flash a message. So we can say with, let's call it message. And let's say post was created. Okay. So we have to add some code to make this flash message work. But for now, let's see if the post is created and we are redirected to that page.
So we have to add some code to make this flash message work. But for now, let's see if the Post is created and we are redirected to that page. So back here, let me just refresh. Let's say title here. body here. Okay. Let's create the Post. We are redirected. There it is there. Let's double check our database.
Flashing Session Messages21:51
There it is there. Let's double check our database. And there it is. Let's take a look at how we can flash the message. So within the documentation, I believe there's a section here for flash messages. So what we want to do is share the data globally in our application. So we can do that within our handleInertiaRequest middleware, and we can add it like this. So let's add this within that middleware. HandleInertiaRequests.
So let's add this within that middleware. Handle Inertia requests. Okay. Let's put that within here. Within the share method. So it's grabbing the message from the session and then making it globally available within Inertia. So let's save this. If we go back to the docs, you can display it like this. You have to make use of the usePage hook right here.
If we go back to the docs, you can display it like this. You have to make use of the use page hook right here. And this has information about the page. So in this case, we're just grabbing the flashMessage right here, and then we're displaying it here. So let's go ahead and do that. We'll do that from within the posts page, because that's where we're displaying the flashMessage. Make sure to import that up here. Let's grab the actual flashMessage from the props.
Make sure to import that up here. Let's grab the actual flash message from the props. So right here. And we can add that message wherever we like. So in this case, I will grab the code from here. It's doing a conditional. And if it exists, then show a message. So we'll add that right here. So let me save this. And let's see if the flash message shows.
So let me save this. And let's see if the flash message shows. So back to our app, let's go back to create here. Let's add another title, another body, let's create the post. And that doesn't seem to show. I'm going to do a hard refresh. Maybe that will do it. So let's try one more time, create again. One more time, another, create post. And this time it did work.
Adding Server Validation23:51
One more time, another, create Post. And this time it did work. So there is the flash message. And this should only appear once. So if I go to another route and come back, sorry, back here, it no longer shows, just like in traditional Laravel. Okay, now let's take a look at validation. And if you go back to the docs for the forms right here, you'll see we have access to this errors object, which should have the errors if there were any. So pretty straightforward.
errors object, which should have the errors if there were any. So pretty straightforward. If you look down here, you'll see how to use it. So if there's an error, show it for that specific field. So we'll do this for both of our fields here. So back to our create JSX, we'll add that error message underneath each field. So one here, title. So this should be title. And one for our body underneath the textarea. This should be body, okay.
And one for our body underneath the text area. This should be body, okay. And we can just perform validation as we would in Laravel. So back to our routes file, we can say request()->validate before we create the post. Okay. And we want to validate the title. Let's say required minimum three characters, and same for the body. Okay. And that should work. We can also save this as a variable and pass it through the create field here or the create.
And that should work. We can also save this as a variable and pass it through the create field here or the create method. But this is fine for me. Okay, save this. And let's see if the errors show up. So back to our app. Back here. Let's go ahead and hit create post. And the errors are showing.
Let's go ahead and hit create post. And the errors are showing. Let's try for the minimum amount of characters. And that's working as well. So again, these are server side errors. But if you want to add client side validation, you can easily do that as well. Since now we are in the context of a React application. Let's just make sure this still works. So let me just add a few characters here. And everything is still working.
