Zápisník Josefa Rouska

Python a React.js programátor, zaměřený na Shopify integrace

Inertia.js, React a Django

Po přechodu na SPA (přibližně před rokem) se naše produktivita nezlepšila i přesto, že jsme tým prakticky zdvojnásobili. Říkal jsem si, že se to časem srovná. Pak přišel DHH s Hotwire, všimnul jsem si HTMX a pak Inertia.js. Většina těchto knihoven používá HTML over the wire přístup. Inertia.js se od nich odlišuje a snaží se definovat protokol, jak by spolu měli React, Vue nebo Svelte aplikace a backend komunikovat. Oficiálně jsou podporované Laravel a Rails. Pro Django ale existuje neoficiální balíček. Tento přístup je pro nás zajímavý hlavně kvůli Polaris - Design Systému od Shopify. Většinu HTML a CSS si nepíšeme sami, ale používáme komponenty připravené Shopify.

A co to tedy vlastně umí? Nahrazuje potřebu mít API a client-side routing. Ve view pouze definuju, jaká komponenta se má použít a jaké props dostane. render_inertia rozhodne jestli vrátí JSON nebo HTML odpověď.

def home(request):
    props = {
        "events": [{
            "id": 1,
            "title": "Title",
            "description": "description, wow"
        }],
    }
    return render_inertia(request, "Home", props)

Pro přechod mezi stránkami existuje komponenta Link. Díky ní Inertia načte pouze data a nedochází k full-page refresh. Ineria totiž pošle požadavek s hlavičkou X-Inertia. Server v takovém případě pošle JSON místo HTML.

Nedílnou součástí každé aplikace jsou formuláře. Inertia proto nabízí helper funkce pro všechny podporované frameworky.

Samotný kód vypadá následovně. V případě Reactu má hook useForm na starosti uchování stavu, odeslání dat na server a validace. Způsob zpracování požadavku je velmi podobný klasickému odeslání formuláře. Pokud je potřeba uživateli zobrazit validační hlášku, stačí do props přidat klíč errors. Inertia helper useForm potom zpřístupní pomocí stejnojmenného klíče.

import React from 'react'
import { Link, useForm } from '@inertiajs/inertia-react'

export default function Create() {
    const { data, setData, post, processing, errors } = useForm({
        email: '',
        password: '',
        remember: false,
    })

    function submit(e) {
        e.preventDefault()
        post('/inertia/create')
    }

    return (
        <div>
            <h2>Create event</h2>
            <Link href="/inertia">Back</Link>
            <form onSubmit={submit}>
                <input type="text" value={data.email} onChange={e => setData('email', e.target.value)} />
                {errors.email && <div>{errors.email}</div>}
                <input type="password" value={data.password} onChange={e => setData('password', e.target.value)} />
                {errors.password && <div>{errors.password}</div>}
                <input type="checkbox" checked={data.remember} onChange={e => setData('remember', e.target.checked)} /> Remember Me
                <button type="submit" disabled={processing}>Login</button>
            </form>
        </div>
    )
}

Zpracování POST requestu na serveru.

from inertia.views import render_inertia
from inertia.share import share, share_flash

def event_create(request):
    if request.method == "POST":
        data = json.loads(request.body)
        if not data["email"]: # Just so there's some validation
            share_flash(request, error=True, errors={"email": ["email can't be empty"]})
        else:
            share_flash(request, success=f"event {data['email']} created")
            return redirect(reverse("inertia_react:index"))

    return render_inertia(request, "Events.Create", {})

Inertia představuje velmi tenkou vrstvu mezi tradičními webovými frameworky a moderními frontendovými frameworky. Možnost použít React místo klasických šablon bez nutnosti vybudovat nejdříve API, je pro mě velmi lákavá. Nemusí to být ani konečný stav. Inertia může být krok mezi jednotlivými komponentami a SPA.