Create React JS CRUD using Vite in Laravel 9 Example

Today, We are going to Create React JS CRUD using Vite in Laravel 9 example. This tutorial will cover about creating , updating, deleting, displaying list of posts using Vite.

What is Vite?

Vite is a modern frontend build tool that provides an extremely fast development environment and bundles your code for production. When building applications with Laravel, you will typically use Vite to bundle your application’s CSS and JavaScript files into production ready assets.

Steps to Create React JS CRUD using Vite in Laravel 9 Example:

  • Step 1: Installing a fresh new Laravel 9
  • Step 2: Creating Database
  • Step 3: Creating AUTH with Breeze
  • Step 4: Creating Migration and Model
  • Step 5: Creating Route
  • Step 6: Creating Controller
  • Step 7: Creating React Pages
  • Step 8: Testing
  • Step 9: Conclusion

Also Read: Datatables Filter with Dropdown in Laravel 9 Example

Step 1: Installing a fresh new Laravel 9

First step, is to install a fresh new Laravel application. To install a Laravel 9 Application using composer run the following command in terminal.

composer create-project laravel/laravel react-js-crud

cd react-js-crud

Note: react-js-crud” is the Laravel 9 application name.

Installing Laravel 9 - Create React JS CRUD using Vite in Laravel 9 Example
Installing a fresh new Laravel 9

Step 2: Creating Database

Now, We are going to create a database. To create a database first open your phpmyadmin and create a new database with name react-js-crud. You can use whatever you like.

Creating Database - Create React JS CRUD using Vite in Laravel 9 Example
Creating Database

Now Open .env file and enter the database details

Add database details to .env file - Create React JS CRUD using Vite in Laravel 9 Example
Add database details to .env file

Step 3: Creating AUTH with Breeze

Now, We are going to install AUTH with Breeze with composer. To install the AUTH with Breeze run the following command into terminal.

composer require laravel/breeze --dev

Now, we need to install the authentication for register, login and logout. If you like to create a team management you have to pass addition parameter. you can see below commands:

php artisan breeze:install react

Now install node js package.

npm install

Now let run the vite by following command.

npm run dev

Its time you to run the migration. Follow the below command to do so.

php artisan migrate
Authentication installation - Create React JS CRUD using Vite in Laravel 9 Example
Authentication installation

Also Read: Ajax File Upload with Progress Bar in Laravel 9 Example

Step 4: Creating Migration and Model

Now, We are going to create a migration for posts. To create a posts migration run the following command.

php artisan make:migration create_posts_table

and enter the following to the migration field.

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('body');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
};
Creating Posts Migration - Create React JS CRUD using Vite in Laravel 9 Example
Creating Posts Migration

Run the Migrate now

php artisan migrate

Now, We are going to create post model. To create a post model run the following command in terminal.

php artisan make:model Post

and enter the following code to the post model.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'title', 'body'
    ];
}
Creating Post Model - Create React JS CRUD using Vite in Laravel 9 Example
Creating Post Model

Step 5: Creating Route

Its time to create routes for react js crud application. So enter the following resource routes.

<?php

use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\PostController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::resource('posts', PostController::class);
   
Route::get('/', function () {
    return Inertia::render('Welcome', [
        'canLogin' => Route::has('login'),
        'canRegister' => Route::has('register'),
        'laravelVersion' => Application::VERSION,
        'phpVersion' => PHP_VERSION,
    ]);
});
    
Route::get('/dashboard', function () {
    return Inertia::render('Dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
   
require __DIR__.'/auth.php';
Creating Resources Routes for the React Js application
Creating Resources Routes for the React Js CRUD application

Also Read: How to Create RSS Feed in Laravel 9 Example

Step 6: Creating Controller

In this step, we will create PostController file and add following code on it.

<?php
   
namespace App\Http\Controllers;
    
use Illuminate\Http\Request;
use Inertia\Inertia;
use App\Models\Post;
use Illuminate\Support\Facades\Validator;
   
class PostController extends Controller
{
    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function index()
    {
        $posts = Post::all();
        return Inertia::render('Posts/Index', ['posts' => $posts]);
    }
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function create()
    {
        return Inertia::render('Posts/Create');
    }
    
    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function store(Request $request)
    {
        Validator::make($request->all(), [
            'title' => ['required'],
            'body' => ['required'],
        ])->validate();
   
        Post::create($request->all());
    
        return redirect()->route('posts.index');
    }
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function edit(Post $post)
    {
        return Inertia::render('Posts/Edit', [
            'post' => $post
        ]);
    }
    
    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function update($id, Request $request)
    {
        Validator::make($request->all(), [
            'title' => ['required'],
            'body' => ['required'],
        ])->validate();
    
        Post::find($id)->update($request->all());
        return redirect()->route('posts.index');
    }
    
    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function destroy($id)
    {
        Post::find($id)->delete();
        return redirect()->route('posts.index');
    }
}
Creating PostController for the React JS Application
Creating PostController for the React JS CRUD Application

Step 7: Creating React Pages

Here, in this step we will create react js file for Index.jsx, Create.jsx and Edit.jsx. so, let’s create it and add bellow code on it.

resources/js/Pages/Posts/Index.jsx

import React from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Inertia } from "@inertiajs/inertia";
import { Head, usePage, Link } from '@inertiajs/inertia-react';
  
export default function Dashboard(props) {
    const { posts } = usePage().props
  
    function destroy(e) {
        if (confirm("Are you sure you want to delete this user?")) {
            Inertia.delete(route("posts.destroy", e.currentTarget.id));
        }
    }
   
    return (
        <Authenticated
            auth={props.auth}
            errors={props.errors}
            header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Posts</h2>}
        >
            <Head title="Posts" />
  
            <div className="py-12">
                <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
                    <div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                        <div className="p-6 bg-white border-b border-gray-200">
  
                            <div className="flex items-center justify-between mb-6">
                                <Link
                                    className="px-6 py-2 text-white bg-green-500 rounded-md focus:outline-none"
                                    href={ route("posts.create") }
                                >
                                    Create Post
                                </Link>
                            </div>
  
                            <table className="table-fixed w-full">
                                <thead>
                                    <tr className="bg-gray-100">
                                        <th className="px-4 py-2 w-20">No.</th>
                                        <th className="px-4 py-2">Title</th>
                                        <th className="px-4 py-2">Body</th>
                                        <th className="px-4 py-2">Action</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {posts.map(({ id, title, body }) => (
                                        <tr>
                                            <td className="border px-4 py-2">{ id }</td>
                                            <td className="border px-4 py-2">{ title }</td>
                                            <td className="border px-4 py-2">{ body }</td>
                                            <td className="border px-4 py-2">
                                                <Link
                                                    tabIndex="1"
                                                    className="px-4 py-2 text-sm text-white bg-blue-500 rounded"
                                                    href={route("posts.edit", id)}
                                                >
                                                    Edit
                                                </Link>
                                                <button
                                                    onClick={destroy}
                                                    id={id}
                                                    tabIndex="-1"
                                                    type="button"
                                                    className="mx-1 px-4 py-2 text-sm text-white bg-red-500 rounded"
                                                >
                                                    Delete
                                                </button>
                                            </td>
                                        </tr>
                                    ))}
  
                                    {posts.length === 0 && (
                                        <tr>
                                            <td
                                                className="px-6 py-4 border-t"
                                                colSpan="4"
                                            >
                                                No contacts found.
                                            </td>
                                        </tr>
                                    )}
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </Authenticated>
    );
}

resources/js/Pages/Posts/Create.jsx

import React from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Head, useForm, Link } from '@inertiajs/inertia-react';
  
export default function Dashboard(props) {
  
    const { data, setData, errors, post } = useForm({
        title: "",
        description: "",
    });
  
    function handleSubmit(e) {
        e.preventDefault();
        post(route("posts.store"));
    }
  
    return (
        <Authenticated
            auth={props.auth}
            errors={props.errors}
            header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Create Post</h2>}
        >
            <Head title="Posts" />
  
            <div className="py-12">
                <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
                    <div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                        <div className="p-6 bg-white border-b border-gray-200">
  
                            <div className="flex items-center justify-between mb-6">
                                <Link
                                    className="px-6 py-2 text-white bg-blue-500 rounded-md focus:outline-none"
                                    href={ route("posts.index") }
                                >
                                    Back
                                </Link>
                            </div>
  
                            <form name="createForm" onSubmit={handleSubmit}>
                                <div className="flex flex-col">
                                    <div className="mb-4">
                                        <label className="">Title</label>
                                        <input
                                            type="text"
                                            className="w-full px-4 py-2"
                                            label="Title"
                                            name="title"
                                            value={data.title}
                                            onChange={(e) =>
                                                setData("title", e.target.value)
                                            }
                                        />
                                        <span className="text-red-600">
                                            {errors.title}
                                        </span>
                                    </div>
                                    <div className="mb-0">
                                        <label className="">Body</label>
                                        <textarea
                                            type="text"
                                            className="w-full rounded"
                                            label="body"
                                            name="body"
                                            errors={errors.body}
                                            value={data.body}
                                            onChange={(e) =>
                                                setData("body", e.target.value)
                                            }
                                        />
                                        <span className="text-red-600">
                                            {errors.body}
                                        </span>
                                    </div>
                                </div>
                                <div className="mt-4">
                                    <button
                                        type="submit"
                                        className="px-6 py-2 font-bold text-white bg-green-500 rounded"
                                    >
                                        Save
                                    </button>
                                </div>
                            </form>
  
                        </div>
                    </div>
                </div>
            </div>
        </Authenticated>
    );
}

resources/js/Pages/Posts/Edit.jsx

import React from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Head, useForm, usePage, Link } from '@inertiajs/inertia-react';
  
export default function Dashboard(props) {
  
    const { post } = usePage().props;
    const { data, setData, put, errors } = useForm({
        title: post.title || "",
        body: post.body || "",
    });
  
    function handleSubmit(e) {
        e.preventDefault();
        put(route("posts.update", post.id));
    }
  
    return (
        <Authenticated
            auth={props.auth}
            errors={props.errors}
            header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Edit Post</h2>}
        >
            <Head title="Posts" />
  
            <div className="py-12">
                <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
                    <div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                        <div className="p-6 bg-white border-b border-gray-200">
  
                            <div className="flex items-center justify-between mb-6">
                                <Link
                                    className="px-6 py-2 text-white bg-blue-500 rounded-md focus:outline-none"
                                    href={ route("posts.index") }
                                >
                                    Back
                                </Link>
                            </div>
  
                            <form name="createForm" onSubmit={handleSubmit}>
                                <div className="flex flex-col">
                                    <div className="mb-4">
                                        <label className="">Title</label>
                                        <input
                                            type="text"
                                            className="w-full px-4 py-2"
                                            label="Title"
                                            name="title"
                                            value={data.title}
                                            onChange={(e) =>
                                                setData("title", e.target.value)
                                            }
                                        />
                                        <span className="text-red-600">
                                            {errors.title}
                                        </span>
                                    </div>
                                    <div className="mb-0">
                                        <label className="">Body</label>
                                        <textarea
                                            type="text"
                                            className="w-full rounded"
                                            label="body"
                                            name="body"
                                            errors={errors.body}
                                            value={data.body}
                                            onChange={(e) =>
                                                setData("body", e.target.value)
                                            }
                                        />
                                        <span className="text-red-600">
                                            {errors.body}
                                        </span>
                                    </div>
                                </div>
                                <div className="mt-4">
                                    <button
                                        type="submit"
                                        className="px-6 py-2 font-bold text-white bg-green-500 rounded"
                                    >
                                        Update
                                    </button>
                                </div>
                            </form>
  
                        </div>
                    </div>
                </div>
            </div>
        </Authenticated>
    );
}

Next, we will add posts module link on header navbar. you have to update add following line on Authenticated.jsx file.

resources/js/Layouts/Authenticated.jsx

...
<NavLink href={route('posts.index')} active={route().current('posts.index')}>
Posts
</NavLink>
...
Creating React Pages
Creating React Pages

Also Read: Create Ajax CRUD Laravel 9 Application Example

Step 8: Testing

Now just test the React JS CRUD using Vite in Laravel 9 Application. Run the following command to run the laravel server.

php artisan serve

Also keep run following command for vite:

npm run dev

If you want to build then you can run following command:

npm run build

Now open the web browser and enter the followin URL and test the application.

http://127.0.0.1:8000/

Note: Please register a new user and login with the details. Click the Posts link at the Navbar.

Previews:

Lists Post:

Post Lists - Create React JS CRUD using Vite in Laravel 9 Example
Post Lists 8211 Create React JS CRUD using Vite in Laravel 9 Example

Create Post:

Create Lists - Create React JS CRUD using Vite in Laravel 9 Example
Create Lists 8211 Create React JS CRUD using Vite in Laravel 9 Example

Edit Post:

Edit Lists - Create React JS CRUD using Vite in Laravel 9 Example
Edit Lists 8211 Create React JS CRUD using Vite in Laravel 9 Example

Step 9: Conclusion

Today, We had learn Create React JS CRUD using Vite in Laravel 9 Example. Hope this tutorial helped you with learning Laravel 9. If you have any question you can ask us at comment section below. If you like the tutorial please subscribe our YouTube Channel and follow us on social network Facebook and Instagram.

Also Read: How to get Country City Address from IP Address Laravel 9

5 Comments

Leave a Reply