Inertia 3.11 มีอะไรใหม่ live props อัปเดตหน้าเว็บเองเมื่อข้อมูลเปลี่ยน

Inertia 3.11 เพิ่ม live props ให้ prop ฟัง broadcast event ของ Laravel แล้วโหลดตัวเองใหม่เมื่อ event มาถึง หน้าติดตามออเดอร์หรือ dashboard จึงเปลี่ยนตามข้อมูลได้ทันทีโดยไม่ต้องตั้ง polling

เผยแพร่
เวลาอ่าน
4 นาที
สรุปจาก
Paul Redmond · laravel-news.com
แท็ก
#Inertia#Laravel
ในโพสต์นี้ 7 หัวข้อ
  1. live props ให้ server บอกหน้าเว็บเมื่อข้อมูลเปลี่ยน
  2. ฝั่ง Laravel ประกาศ prop ด้วย Inertia::live()
  3. ฝั่ง React ตั้ง transport ครั้งเดียวใน app.jsx
  4. Inertia กันไม่ให้ event ถี่ ๆ ยิง request ตาม
  5. ส่งค่าใหม่ไปกับ event ได้ ถ้าทุกคนในช่องดูค่านั้นได้
  6. ของเล็ก ๆ ที่มาพร้อม live props
  7. usePoll ยังเหมาะกับเว็บบน shared hosting

ที่ผ่านมา ถ้าอยากให้หน้ารายละเอียดออเดอร์เปลี่ยนสถานะเองตอน job ตรวจสลิปทำงานเสร็จ เราก็มักใช้ usePoll() ให้หน้าเว็บถาม server ทุก 5 วินาที (แบบในโพสต์ Inertia 3.9) ก็ใช้ได้นะ แต่ request ส่วนใหญ่ได้คำตอบว่ายังเหมือนเดิม และสถานะใหม่ก็อาจมาช้าไปเกือบหนึ่งรอบ

live props ให้ server บอกหน้าเว็บเมื่อข้อมูลเปลี่ยน

live props กลับทิศกัน หน้าเว็บไม่ต้องถาม server คอยส่งสัญญาณผ่าน broadcasting ของ Laravel แทน browser เปิด WebSocket ค้างไว้กับ Reverb พอ job ทำงานเสร็จแล้ว broadcast event OrderUpdated ออกมา Inertia ที่ฟังอยู่ก็ขอเฉพาะ prop order ใหม่จาก controller ตัวเดิม (partial reload) เหมือนเรากดโหลดใหม่แค่ส่วนนั้นของหน้า

ลำดับที่ live prop อัปเดตหน้าเว็บ ตั้งแต่ job ทำงานเสร็จ

Inertia ขอข้อมูลใหม่เฉพาะตอนที่มี event มาถึง ไม่ต้องถามซ้ำตามรอบเวลา

ฝั่ง Laravel ประกาศ prop ด้วย Inertia::live()

ใน controller ห่อ prop ด้วย Inertia::live() แล้วบอกใน on: ว่าให้ฟัง event ตัวไหน Inertia อ่าน channel จาก broadcastOn() ของ event นั้นเอง เราไม่ต้องเขียนชื่อ channel ซ้ำ

use App\Events\OrderUpdated;
use Inertia\Inertia;

return Inertia::render('Orders/Show', [
    'order' => Inertia::live(fn () => $order->fresh(), on: new OrderUpdated($order)),
]);
  • ใช้คู่กับ prop แบบอื่นได้ ต่อ ->live() ท้าย Inertia::defer(), once(), optional() หรือ always() ได้เลย ยกเว้น merge props ที่เป็น live ไม่ได้ ส่วน optional prop จะโหลดใหม่ก็ต่อเมื่อหน้าเคยโหลด prop นั้นมาแล้ว
  • ฟังหลาย event ส่งเป็น array เช่น on: [new OrderUpdated($order), new OrderShipped($order)] prop ที่ฟัง event เดียวกันจะโหลดใหม่พร้อมกันใน request เดียว
  • เลือก channel เอง event ที่ broadcast ไปทั้ง orders.1 และ orders จะทำให้ prop โหลดใหม่ทุกครั้งที่ออเดอร์ไหนก็ตามเปลี่ยน ถ้าอยากฟังแค่ช่องเดียว ใส่ channel: new PrivateChannel('orders.1') เพิ่ม
  • ส่งชื่อ class แทน instance ได้ เช่น on: OrderUpdated::class แต่ใช้ได้เฉพาะ event ที่ชื่อ channel ไม่ขึ้นกับข้อมูลข้างใน เพราะ Inertia สร้าง event ขึ้นมาโดยไม่เรียก constructor

private channel และ presence channel ใช้สิทธิ์ตามที่เขียนไว้ใน routes/channels.php เหมือนเดิม ไม่มีอะไรต้องตั้งเพิ่ม

ฝั่ง React ตั้ง transport ครั้งเดียวใน app.jsx

Inertia ต้องรู้ว่าจะฟัง event ผ่านอะไร เรียกว่า transport ถ้าตั้ง broadcasting ด้วย Reverb กับ Echo ไว้แล้ว ใส่ echo() ลงใน option live ของ createInertiaApp()

import { createInertiaApp } from '@inertiajs/react'
import { echo } from '@inertiajs/react/echo'
import { configureEcho } from '@laravel/echo-react'

configureEcho({ broadcaster: 'reverb' })

createInertiaApp({
    live: echo(),
    // ...
})

@laravel/echo-react เป็น optional peer dependency แอปที่ไม่ได้ใช้ live props จึงไม่ต้องลง ถ้าสร้าง Echo เองด้วย laravel-echo อยู่แล้ว ส่ง echo({ resolve: () => window.Echo }) แทนได้ Inertia จะ subscribe และเลิก subscribe channel ให้เองตอนผู้ใช้เปลี่ยนหน้า

ถ้าไม่ได้ใช้ Echo ก็ยังมี pusher() สำหรับ server ที่คุย protocol ของ Pusher ได้ (Reverb ก็นับด้วย) แต่ต้องตั้งสิทธิ์ของ channel ใน client เอง และมี actionCable() สำหรับฝั่ง Rails หรือจะเขียน transport เองจาก WebSocket ตัวอื่นหรือ server-sent events ก็ได้ ตามแบบในเอกสาร

Inertia กันไม่ให้ event ถี่ ๆ ยิง request ตาม

ถ้า event มาถี่ เช่นมีออเดอร์เข้าทีละหลายสิบรายการ การโหลดใหม่ทุกครั้งที่มี event ก็จะยิง request ถี่ตามไปด้วย Inertia จึงคุมไว้ให้ตั้งแต่แรก

เรื่อง Inertia ทำอะไร
ความถี่ แต่ละ prop โหลดใหม่ได้ไม่เกินวินาทีละครั้ง event ที่มาระหว่างนั้นรวมเป็น request เดียวตอนครบเวลา ปรับได้ด้วย throttle (มิลลิวินาที) ทั้งที่ echo({ throttle: 2000 }) และราย prop
หลาย event จาก action เดียว รอไม่กี่มิลลิวินาทีก่อนโหลด แล้วรวมทุก prop ที่โดนในครั้งนั้นเป็น request เดียว
แท็บอยู่เบื้องหลัง หยุดโหลดจนกว่าผู้ใช้จะกลับมา ถ้าอยากให้โหลดต่อ ใส่ pauseWhenHidden: false
WebSocket หลุดแล้วต่อใหม่ โหลดทุก live prop ใหม่ เพราะ event ที่ส่งมาตอนหลุดไม่มีทางมาถึง

router.reload() ที่เราเรียกเองไม่โดน throttle

ส่งค่าใหม่ไปกับ event ได้ ถ้าทุกคนในช่องดูค่านั้นได้

ปกติแต่ละหน้าที่ฟังอยู่จะยิง request กลับมาขอค่าใหม่ ลองนึกถึง dashboard ที่เปิดค้างไว้ 1,000 แท็บ event เดียวจะกลายเป็น 1,000 request ทันที ทางแก้คือใส่ค่าใหม่ไปกับ event เลยด้วย Inertia::broadcastProps() แล้ว Inertia จะเขียนค่านั้นลงหน้าโดยไม่ขอ server อีก

public function broadcastWith(): array
{
    return [
        'order_id' => $this->order->id,
        ...Inertia::broadcastProps([
            'order' => OrderResource::make($this->order),
        ]),
    ];
}

ของเล็ก ๆ ที่มาพร้อม live props

  • useProp('order') คืน value พร้อม loading ระหว่างที่ prop กำลังโหลดใหม่ เอาไปทำหน้าจางลงนิดหนึ่งให้ผู้ใช้รู้ว่ากำลังอัปเดต และมี loaded สำหรับ prop ที่เป็นทั้ง deferred และ live
  • event live ของ router ยิงก่อนอัปเดต prop และยกเลิกได้ด้วยการคืน false เช่นหน้าที่ผู้ใช้กำลังกรอกฟอร์มอยู่ อาจขึ้นปุ่ม "มีข้อมูลใหม่" ให้กดเองแทนการเปลี่ยนหน้าจอใต้มือผู้ใช้
  • toOthers() ใช้ได้เลย Inertia ส่ง header X-Socket-Id ไปกับ request ที่อยู่ origin เดียวกัน broadcast(new OrderUpdated($order))->toOthers() จึงไม่ส่ง event กลับมาหาคนที่เพิ่งกดบันทึก

usePoll ยังเหมาะกับเว็บบน shared hosting

live props ต้องมีสองอย่างรันค้างอยู่บนเซิร์ฟเวอร์ตลอด คือ Reverb (หรือบริการอย่าง Pusher) กับ queue worker ที่ส่ง event ออกไป ถ้าเว็บอยู่บน shared hosting ที่ใช้ cPanel หรือ DirectAdmin ซึ่งรัน process ค้างไม่ได้ usePoll() กับ background: 'pause' ยังเป็นทางที่ง่ายกว่า ส่วนเว็บที่อยู่บน VPS อยู่แล้ว live props ช่วยลด request ที่ไม่จำเป็นได้เยอะ และหน้าจอก็เปลี่ยนทันทีที่ข้อมูลเปลี่ยน

อัปเดตทั้งสองฝั่งพร้อมกัน

composer require inertiajs/inertia-laravel:^3.7
npm install @inertiajs/react@^3.11 @laravel/echo-react

รายละเอียดทั้งหมดอยู่ในบทความต้นฉบับ option ครบทุกตัวและวิธีเขียน transport เองอยู่ในเอกสาร Live Props ส่วนรายการเปลี่ยนแปลงอยู่ใน release notes ของ v3.11.0

อ่านต่อ

ถูกอ้างถึงใน

ล่าสุด

ดูทั้งหมด →