04. Menampilkan Chirp
Pada langkah sebelumnya kita telah menambahkan kemampuan untuk membuat Chirp, sekarang kita siap untuk menampilkannya!
Mengambil Data Chirp
Mari kita perbarui metode index pada kelas ChirpController untuk mengirimkan data Chirp dari setiap pengguna ke halaman Index kita:
<?php
namespace App\Http\Controllers; use App\Models\Chirp; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Inertia\Inertia; use Inertia\Response; class ChirpController extends Controller { /** * Menampilkan daftar resource. */ public function index(): Response { return Inertia::render('Chirps/Index', [- //+ 'chirps' => Chirp::with('user:id,name')->latest()->get(), ]); }
/** * Menampilkan formulir untuk membuat resource baru. */ public function create() { // } /** * Menyimpan resource yang baru dibuat ke dalam penyimpanan. */ public function store(Request $request): RedirectResponse { $validated = $request->validate([ 'message' => 'required|string|max:255', ]); $request->user()->chirps()->create($validated); return redirect(route('chirps.index')); } /** * Menampilkan resource yang dipilih/spesifik. */ public function show(Chirp $chirp) { // } /** * Menampilkan formulir untuk mengedit resource yang dipilih/spesifik. */ public function edit(Chirp $chirp) { // } /** * Memperbarui resource yang dipilih/spesifik di dalam penyimpanan. */ public function update(Request $request, Chirp $chirp) { // } /** * Menghapus resource yang dipilih/spesifik dari penyimpanan. */ public function destroy(Chirp $chirp) { // } }
Di sini kita menggunakan metode with milik Eloquent untuk melakukan eager-load terhadap ID dan nama pengguna yang terkait dengan setiap Chirp. Kita juga menggunakan scope latest untuk mengembalikan data dengan urutan kronologis terbalik (terbaru di atas).
Mengembalikan semua Chirp sekaligus tidak akan optimal untuk lingkungan produksi. Silakan pelajari fitur pagination Laravel yang mumpuni untuk meningkatkan performa.
Menghubungkan Pengguna ke Chirp
Kita telah menginstruksikan Laravel untuk mengembalikan properti id dan name dari relasi user sehingga kita dapat menampilkan nama penulis Chirp tanpa mengembalikan informasi sensitif lainnya seperti alamat email penulis. Namun, relasi user pada model Chirp belum didefinisikan. Untuk memperbaikinya, mari kita tambahkan relasi "belongs to" baru ke model Chirp kita:
<?php
namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model;+use Illuminate\Database\Eloquent\Relations\BelongsTo; class Chirp extends Model {
use HasFactory; protected $fillable = [ 'message', ]; + public function user(): BelongsTo+ {+ return $this->belongsTo(User::class);+ } }
Relasi ini adalah kebalikan dari relasi "has many" yang kita buat sebelumnya pada model User.
Memperbarui Komponen
Selanjutnya, mari kita buat komponen Chirp untuk front-end kita. Komponen ini akan bertanggung jawab untuk menampilkan setiap butir Chirp secara individual:
<script setup>defineProps(['chirp']);</script> <template> <div class="p-6 flex space-x-2"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-600 -scale-x-100" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" /> </svg> <div class="flex-1"> <div class="flex justify-between items-center"> <div> <span class="text-gray-800">{{ chirp.user.name }}</span> <small class="ml-2 text-sm text-gray-600">{{ new Date(chirp.created_at).toLocaleString() }}</small> </div> </div> <p class="mt-4 text-lg text-gray-900">{{ chirp.message }}</p> </div> </div></template>
import React from 'react'; export default function Chirp({ chirp }) { return ( <div className="p-6 flex space-x-2"> <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-gray-600 -scale-x-100" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"> <path strokeLinecap="round" strokeLinejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" /> </svg> <div className="flex-1"> <div className="flex justify-between items-center"> <div> <span className="text-gray-800">{chirp.user.name}</span> <small className="ml-2 text-sm text-gray-600">{new Date(chirp.created_at).toLocaleString()}</small> </div> </div> <p className="mt-4 text-lg text-gray-900">{chirp.message}</p> </div> </div> );}
Terakhir, kita akan memperbarui komponen halaman Chirps/Index untuk menerima prop chirps dan menampilkan daftar Chirp di bawah formulir menggunakan komponen baru kita:
<script setup> import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';+import Chirp from '@/Components/Chirp.vue'; import InputError from '@/Components/InputError.vue'; import PrimaryButton from '@/Components/PrimaryButton.vue'; import { useForm, Head } from '@inertiajs/vue3'; +defineProps(['chirps']); const form = useForm({ message: '', }); </script> <template> <Head title="Dashboard" /> <AuthenticatedLayout> <div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"> <form @submit.prevent="form.post(route('chirps.store'), { onSuccess: () => form.reset() })"> <textarea v-model="form.message" placeholder="What's on your mind?" class="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" ></textarea> <InputError :message="form.errors.message" class="mt-2" /> <PrimaryButton class="mt-4">Chirp</PrimaryButton> </form> + <div class="mt-6 bg-white shadow-sm rounded-lg divide-y">+ <Chirp+ v-for="chirp in chirps"+ :key="chirp.id"+ :chirp="chirp"+ />+ </div> </div> </AuthenticatedLayout> </template>
import React from 'react'; import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';+import Chirp from '@/Components/Chirp'; import InputError from '@/Components/InputError'; import PrimaryButton from '@/Components/PrimaryButton'; import { useForm, Head } from '@inertiajs/react'; -export default function Index({ auth }) {+export default function Index({ auth, chirps }) { const { data, setData, post, processing, reset, errors } = useForm({ message: '', }); const submit = (e) => { e.preventDefault(); post(route('chirps.store'), { onSuccess: () => reset() }) }; return ( <AuthenticatedLayout> <Head title="Chirps" /> <div className="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"> <form onSubmit={submit}> <textarea value={data.message} placeholder="What's on your mind?" className="block w-full border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" onChange={e => setData('message', e.target.value)} ></textarea> <InputError message={errors.message} className="mt-2" /> <PrimaryButton className="mt-4" disabled={processing}>Chirp</PrimaryButton> </form> + <div className="mt-6 bg-white shadow-sm rounded-lg divide-y">+ {chirps.map(chirp =>+ <Chirp key={chirp.id} chirp={chirp} />+ )}+ </div> </div> </AuthenticatedLayout> ); }
Sekarang lihatlah di peramban Anda untuk melihat pesan yang Anda Chirp-kan tadi!
Nilai Tambah: Tanggal Relatif
Di komponen Chirp, kita memformat tanggal agar mudah dibaca, tetapi kita bisa melangkah lebih jauh dengan menampilkan tanggal relatif menggunakan pustaka Day.js yang populer.
Pertama, instal paket NPM dayjs:
npm install dayjs
Kemudian kita dapat menggunakan pustaka ini di komponen Chirp untuk menampilkan tanggal relatif:
<script setup>+import dayjs from 'dayjs';+import relativeTime from 'dayjs/plugin/relativeTime'; +dayjs.extend(relativeTime); defineProps(['chirp']); </script> <template> <div class="p-6 flex space-x-2"> <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-gray-600 -scale-x-100" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" /> </svg> <div class="flex-1"> <div class="flex justify-between items-center"> <div> <span class="text-gray-800">{{ chirp.user.name }}</span>- <small class="ml-2 text-sm text-gray-600">{{ new Date(chirp.created_at).toLocaleString() }}</small>+ <small class="ml-2 text-sm text-gray-600">{{ dayjs(chirp.created_at).fromNow() }}</small> </div> </div> <p class="mt-4 text-lg text-gray-900">{{ chirp.message }}</p> </div> </div> </template>
import React from 'react';+import dayjs from 'dayjs';+import relativeTime from 'dayjs/plugin/relativeTime'; +dayjs.extend(relativeTime); export default function Chirp({ chirp }) { return ( <div className="p-6 flex space-x-2"> <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 text-gray-600 -scale-x-100" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth="2"> <path strokeLinecap="round" strokeLinejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" /> </svg> <div className="flex-1"> <div className="flex justify-between items-center"> <div> <span className="text-gray-800">{chirp.user.name}</span>- <small className="ml-2 text-sm text-gray-600">{new Date(chirp.created_at).toLocaleString()}</small>+ <small className="ml-2 text-sm text-gray-600">{dayjs(chirp.created_at).fromNow()}</small> </div> </div> <p className="mt-4 text-lg text-gray-900">{chirp.message}</p> </div> </div> ); }
Lihat kembali di peramban untuk melihat tanggal relatif Anda.
Jangan ragu untuk membuat lebih banyak Chirp, atau bahkan daftarkan akun lain dan mulailah percakapan!