demo: https://inertia-react.ciptacode.dev/
Inertia.js merupakan adapter yang menghubungkan antara backend dan frontend tanpa perlu menggunakan Rest API.
composer create-project --prefer-dist laravel/laravel:9.3.0 inertia-react
cd inertia-react
php artisan serve
Sekarang lakukan konfigurasi koneksi database-nya di dalam Laravel. Silahkan buka file .env, kemudian cari kode berikut ini.
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
Dan ubahlah menjadi seperti berikut ini.
DB_DATABASE=db_inertia_react
DB_USERNAME=root
DB_PASSWORD=
Silahkan buka http://localhost/phpmyadmin, kemudian buat database baru dengan nama db_inertia_react.
Buat Model dan Migration untuk table posts.
php artisan make:model Post -m
Silahkan buka file database/migrations/2022_09_14_014412_create_posts_table.php, kemudian pada function up silahkan ubah menjadi seperti berikut ini.
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
Silahkan buka file app/Models/Post.php, kemudian ubah kode-nya menjadi seperti berikut ini.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
/**
* fillable
*
* @var array
*/
protected $guarded = [];
}
php artisan migrate
membuat project Laravel baru beserta melakukan konfigurasi database telah selesai.
composer require inertiajs/inertia-laravel:0.6.3
php artisan inertia:middleware
Silahkan buka file app/Http/Kernel.php, kemudian tambahkan kode berikut ini di dalam $middlewareGroups dan di dalam array web.
protected $middlewareGroups = [
'web' => [
//...
\App\Http\Middleware\HandleInertiaRequests::class,
],
'api' => [
//...
]
]
Sekarang silahkan buka file app/Http/Middleware/handleInertiaRequest.php, kemudian cari kode berikut ini :
public function share(Request $request): array
{
return array_merge(parent::share($request), [
//
]);
}
kemudian ubahlah menjadi seperti berikut ini.
public function share(Request $request): array
{
return array_merge(parent::share($request), [
//session
'session' => [
'success' => fn () => $request->session()->get('success'),
],
]);
}
Silahkan buat file baru dengan nama app.blade.php di dalam folder resources/views, kemudian masukkan kode berikut ini di dalamnya.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
@viteReactRefresh
@vite('resources/js/app.jsx')
@inertiaHead
<style>
body {
background-color: lightgray
}
</style>
</head>
<body>
@inertia
</body>
</html>
konfigurasi Inertia.js di Laravel secara server side telah selesai.
jalankan perintah berikut ini di dalam terminal/CMD
npm install
npm install @inertiajs/[email protected]
npm install @inertiajs/[email protected]
npm install @inertiajs/[email protected]
npm install [email protected] [email protected]
rename file resources/js/app.js menjadi resources/js/app.jsx, kemudian masukkan kode berikut ini di dalamnya.
import React from 'react';
import { render } from 'react-dom';
import { createInertiaApp } from '@inertiajs/inertia-react';
import { InertiaProgress } from '@inertiajs/progress';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
createInertiaApp({
resolve: (name) => resolvePageComponent(`./Pages/${name}.jsx`, import.meta.glob('./Pages/**/*.jsx')),
setup({ el, App, props }) {
return render(<App {...props} />, el);
},
});
InertiaProgress.init();
buka file vite.config.js, kemudian ubah kode-nya menjadi seperti berikut ini.
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel(['resources/js/app.jsx']),
],
resolve: {
alias: {
'@': '/resources/js',
},
},
});
npm run dev
installasi dan konfigurasi Inertia.js telah selesai.
php artisan make:controller PostController
kita akan mendapatkan 1 file controller baru yang berada di dalam folder app/Http/Controllers/PostController.php.
Silahkan buka file tersebut dan ubah kode-nya menjadi seperti berikut ini :
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* index
*
* @return void
*/
public function index()
{
//get all posts
$posts = Post::latest()->get();
//return view
return inertia('Posts/Index', [
'posts' => $posts
]);
}
}
buka file routes/web.php, kemudian ubah kode-nya menjadi seperti berikut ini.
<?php
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
/**
* route resource /posts
*/
Route::resource('/posts', \App\Http\Controllers\PostController::class);
Silahkan buat folder baru dengan nama Layouts di dalam folder resources/js. Kemudian di dalam folder Layouts buatlah file baru dengan nama Default.jsx dan masukkan kode berikut ini di dalamnya.
//import React
import React from 'react';
//import Link
import { Link } from '@inertiajs/inertia-react';
function Layout({ children }) {
return (
<>
<header>
<nav className="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div className="container">
<Link className="navbar-brand" href="/">LARAVEL + INERTIA.JS</Link>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarCollapse">
<ul className="navbar-nav me-auto mb-2 mb-md-0">
<li className="nav-item">
<Link className="nav-link" href="/posts/">POSTS</Link>
</li>
</ul>
<form className="d-flex">
<input className="form-control me-2" type="search" placeholder="Search" aria-label="Search"/>
<button className="btn btn-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
</header>
<main className="container mt-5">
{ children }
</main>
</>
)
}
export default Layout
Silahkan buat folder baru dengan nama Posts di dalam folder resources/js/Pages, kemudian di dalam folder Posts silahkan buat file baru dengan nama Index.jsx dn masukkan kode berikut ini di dalamnya.
//import React
import React from 'react';
//import layout
import Layout from '../../Layouts/Default';
//import Link
import { Link } from '@inertiajs/inertia-react';
export default function PostIndex({ posts, session }) {
return (
<Layout>
<div style={{ marginTop: '100px' }}>
<Link href="/posts/create" className="btn btn-success btn-md mb-3">TAMBAH POST</Link>
{session.success && (
<div className="alert alert-success border-0 shadow-sm rounded-3">
{session.success}
</div>
)}
<div className="card border-0 rounded shadow-sm">
<div className="card-body">
<table className="table table-bordered table-striped">
<thead>
<tr>
<th scope="col">TITLE</th>
<th scope="col">CONTENT</th>
<th scope="col">ACTIONS</th>
</tr>
</thead>
<tbody>
{ posts.map((post, index) => (
<tr key={ index }>
<td>{ post.title }</td>
<td>{ post.content }</td>
<td className="text-center">
</td>
</tr>
)) }
</tbody>
</table>
</div>
</div>
</div>
</Layout>
)
}
buka di http://localhost:8000/posts, pastikan berhasil.
Silahkan buka file app/Http/Controllers/PostController.php, kemudian ubah kode-nya menjadi seperti berikut ini.
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* index
*
* @return void
*/
public function index()
{
//get all posts
$posts = Post::latest()->get();
//return view
return inertia('Posts/Index', [
'posts' => $posts
]);
}
/**
* create
*
* @return void
*/
public function create()
{
return inertia('Posts/Create');
}
/**
* store
*
* @param mixed $request
* @return void
*/
public function store(Request $request)
{
//set validation
$request->validate([
'title' => 'required',
'content' => 'required',
]);
//create post
Post::create([
'title' => $request->title,
'content' => $request->content
]);
//redirect
return redirect()->route('posts.index')->with('success', 'Data Berhasil Disimpan!');
}
}
Silahkan buat file baru dengan nama Create.jsx di dalam folder resources/js/Pages/Posts, kemudian masukkan kode berikut ini di dalamnya.
//import hook useState from react
import React, { useState } from 'react';
//import layout
import Layout from '../../Layouts/Default';
//import inertia adapter
import { Inertia } from '@inertiajs/inertia';
export default function CreatePost({ errors }) {
//define state
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
//function "storePost"
const storePost = async (e) => {
e.preventDefault();
Inertia.post('/posts', {
title: title,
content: content
});
}
return (
<Layout>
<div className="row" style={{ marginTop: '100px' }}>
<div className="col-12">
<div className="card border-0 rounded shadow-sm border-top-success">
<div className="card-header">
<span className="font-weight-bold">TAMBAH POST</span>
</div>
<div className="card-body">
<form onSubmit={storePost}>
<div className="mb-3">
<label className="form-label fw-bold">Title</label>
<input type="text" className="form-control" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Masukkan Judul Post" />
</div>
{errors.title && (
<div className="alert alert-danger">
{errors.title}
</div>
)}
<div className="mb-3">
<label className="form-label fw-bold">Content</label>
<textarea className="form-control" value={content} onChange={(e) => setContent(e.target.value)} placeholder="Masukkan Judul Post" rows={4}></textarea>
</div>
{errors.content && (
<div className="alert alert-danger">
{errors.content}
</div>
)}
<div>
<button type="submit" className="btn btn-md btn-success me-2"><i className="fa fa-save"></i> SAVE</button>
<button type="reset" className="btn btn-md btn-warning"><i className="fa fa-redo"></i> RESET</button>
</div>
</form>
</div>
</div>
</div>
</div>
</Layout>
)
}
Silahkan klik button TAMBAH POST yang ada pada halaman posts index, pastikan berhasil
tambahkan 2 method baru di dalam controller. buka file app/Http/Controllers/PostController.php, kemudian ubah kode-nya menjadi seperti berikut ini.
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* index
*
* @return void
*/
public function index()
{
//get all posts
$posts = Post::latest()->get();
//return view
return inertia('Posts/Index', [
'posts' => $posts
]);
}
/**
* create
*
* @return void
*/
public function create()
{
return inertia('Posts/Create');
}
/**
* store
*
* @param mixed $request
* @return void
*/
public function store(Request $request)
{
//set validation
$request->validate([
'title' => 'required',
'content' => 'required',
]);
//create post
Post::create([
'title' => $request->title,
'content' => $request->content
]);
//redirect
return redirect()->route('posts.index')->with('success', 'Data Berhasil Disimpan!');
}
/**
* edit
*
* @param mixed $post
* @return void
*/
public function edit(Post $post)
{
return inertia('Posts/Edit', [
'post' => $post,
]);
}
/**
* update
*
* @param mixed $request
* @param mixed $post
* @return void
*/
public function update(Request $request, Post $post)
{
//set validation
$request->validate([
'title' => 'required',
'content' => 'required',
]);
//update post
$post->update([
'title' => $request->title,
'content' => $request->content
]);
//redirect
return redirect()->route('posts.index')->with('success', 'Data Berhasil Diupdate!');
}
}
Silahkan buka file resources/js/Pages/Posts/Index.jsx, kemudian cari kode berikut ini.
{ posts.map((post, index) => (
<tr key={ index }>
<td>{ post.title }</td>
<td>{ post.content }</td>
<td className="text-center">
</td>
</tr>
)) }
Dan ubahlah menjadi seperti berikut ini.
{ posts.map((post, index) => (
<tr key={ index }>
<td>{ post.title }</td>
<td>{ post.content }</td>
<td className="text-center">
<Link href={`/posts/${post.id}/edit`} className="btn btn-sm btn-primary me-2">EDIT</Link>
</td>
</tr>
)) }
buat file baru dengan nama Edit.jsx di dalam folder resources/js/Pages/Posts, kemudian masukkan kode berikut ini di dalamnya.
//import hook useState from react
import React, { useState } from 'react';
//import layout
import Layout from '../../Layouts/Default';
//import inertia adapter
import { Inertia } from '@inertiajs/inertia';
export default function EditPost({ errors, post }) {
//define state
const [title, setTitle] = useState(post.title);
const [content, setContent] = useState(post.content);
//function "updatePost"
const updatePost = async (e) => {
e.preventDefault();
Inertia.put(`/posts/${post.id}`, {
title: title,
content: content
});
}
return (
<Layout>
<div className="row" style={{ marginTop: '100px' }}>
<div className="col-12">
<div className="card border-0 rounded shadow-sm border-top-success">
<div className="card-header">
<span className="font-weight-bold">EDIT POST</span>
</div>
<div className="card-body">
<form onSubmit={updatePost}>
<div className="mb-3">
<label className="form-label fw-bold">Title</label>
<input type="text" className="form-control" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Masukkan Judul Post" />
</div>
{errors.title && (
<div className="alert alert-danger">
{errors.title}
</div>
)}
<div className="mb-3">
<label className="form-label fw-bold">Content</label>
<textarea className="form-control" value={content} onChange={(e) => setContent(e.target.value)} placeholder="Masukkan Judul Post" rows={4}></textarea>
</div>
{errors.content && (
<div className="alert alert-danger">
{errors.content}
</div>
)}
<div>
<button type="submit" className="btn btn-md btn-success me-2"><i className="fa fa-save"></i> UPDATE</button>
<button type="reset" className="btn btn-md btn-warning"><i className="fa fa-redo"></i> RESET</button>
</div>
</form>
</div>
</div>
</div>
</div>
</Layout>
)
}
Silahkan klik button EDIT dan pastikan berhasil
tambahkan method destroy di dalam controller. buka file app/Http/Controllers/PostController.php, kemudian ubah kode-nya menjadi seperti berikut ini.
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* index
*
* @return void
*/
public function index()
{
//get all posts
$posts = Post::latest()->get();
//return view
return inertia('Posts/Index', [
'posts' => $posts
]);
}
/**
* create
*
* @return void
*/
public function create()
{
return inertia('Posts/Create');
}
/**
* store
*
* @param mixed $request
* @return void
*/
public function store(Request $request)
{
//set validation
$request->validate([
'title' => 'required',
'content' => 'required',
]);
//create post
Post::create([
'title' => $request->title,
'content' => $request->content
]);
//redirect
return redirect()->route('posts.index')->with('success', 'Data Berhasil Disimpan!');
}
/**
* edit
*
* @param mixed $post
* @return void
*/
public function edit(Post $post)
{
return inertia('Posts/Edit', [
'post' => $post,
]);
}
/**
* update
*
* @param mixed $request
* @param mixed $post
* @return void
*/
public function update(Request $request, Post $post)
{
//set validation
$request->validate([
'title' => 'required',
'content' => 'required',
]);
//update post
$post->update([
'title' => $request->title,
'content' => $request->content
]);
//redirect
return redirect()->route('posts.index')->with('success', 'Data Berhasil Diupdate!');
}
/**
* destroy
*
* @param mixed $post
* @return void
*/
public function destroy(Post $post)
{
//delete post
$post->delete();
//redirect
return redirect()->route('posts.index')->with('success', 'Data Berhasil Dihapus!');
}
}
buka file resources/js/Pages/Posts/Index.jsx, kemudian ubah kode-nya menjadi seperti berikut ini.
//import React
import React from 'react';
//import layout
import Layout from '../../Layouts/Default';
//import Link
import { Link } from '@inertiajs/inertia-react';
//import inertia adapter
import { Inertia } from '@inertiajs/inertia';
export default function PostIndex({ posts, session }) {
//method deletePost
const deletePost = async (id) => {
Inertia.delete(`/posts/${id}`);
}
return (
<Layout>
<div style={{ marginTop: '100px' }}>
<Link href="/posts/create" className="btn btn-success btn-md mb-3">TAMBAH POST</Link>
{session.success && (
<div className="alert alert-success border-0 shadow-sm rounded-3">
{session.success}
</div>
)}
<div className="card border-0 rounded shadow-sm">
<div className="card-body">
<table className="table table-bordered table-striped">
<thead>
<tr>
<th scope="col">TITLE</th>
<th scope="col">CONTENT</th>
<th scope="col">ACTIONS</th>
</tr>
</thead>
<tbody>
{ posts.map((post, index) => (
<tr key={ index }>
<td>{ post.title }</td>
<td>{ post.content }</td>
<td className="text-center">
<Link href={`/posts/${post.id}/edit`} className="btn btn-sm btn-primary me-2">EDIT</Link>
<button onClick={() => deletePost(post.id)} className="btn btn-sm btn-danger">DELETE</button>
</td>
</tr>
)) }
</tbody>
</table>
</div>
</div>
</div>
</Layout>
)
}
klik button delete dan pastikan berhasil