Next.js 15 -fullstack-kehitys (App Router + Server Actions) · Oppitunti

Odotus- ja lataustilat useFormStatusilla

Poistakaa painikkeet käytöstä ja näyttäkää latausilmaisimet lähetyksen aikana käyttämällä useFormStatus-hookia lomakkeen lapsikomponenteissa.

Oppitunti 2/413 vaihetta

Odotus- ja lataustilat useFormStatusilla on ilmainen Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Next.js 15 -fullstack-kehitys (App Router + Server Actions)-kurssilla on yhteensä 4 oppituntia.

Miksi odotustiloilla on merkitystä

Kun käyttäjä lähettää Server Actionin taustalla olevan lomakkeen, toiminnon suorittaminen palvelimella aiheuttaa verkkopyynnön ja vastauksen välisen viiveen. Ilman palautetta käyttäjä saattaa napsauttaa Lähetä-painiketta kahdesti ja luoda päällekkäisiä tietueita.

  • Poistakaa lähetyspainike käytöstä actionin suorituksen ajaksi.
  • Näyttäkää latauskuvake tai Tallennetaan...-teksti, jotta käyttöliittymä tuntuu reagoivalta.
  • Estäkää kaksoislähetykset automaattisesti.

Next.js 15 (joka perustuu React 19:ään) tarjoaa juuri tätä varten oman hookin: useFormStatus.

Tutustuminen useFormStatusiin

useFormStatus on react-dom-paketista tuotava React-hook. Se ilmoittaa lähimmän ylemmän tason <form>-elementin tilan.

Se palauttaa objektin, jossa on seuraavat kentät:

  • pending — true, kun lomaketta lähetetään.
  • data — lähetettävä FormData.
  • method — HTTP-metodi (get tai post).
  • action — lomakkeen action-propille välitetty funktio tai URL-osoite.

Latauskäyttöliittymää rakentaessanne käytätte useimmiten pending-kenttää.

import { useFormStatus } from "react-dom";

// Returns: { pending, data, method, action }
const { pending } = useFormStatus();

Kultainen sääntö: kutsukaa sitä lapsikomponentin sisältä

Tärkein sääntö: useFormStatus-hookia on kutsuttava komponentista, joka renderöidään <form>-elementin sisällä, ei komponentista, joka itse renderöi <form>-elementin.

Hook lukee ylemmän tason lomakkeen tilan. Jos kutsutte sitä samassa komponentissa, joka sisältää <form>-tagin, sillä ei ole seurattavaa ylemmän tason lomaketta ja pending pysyy aina arvossa false.

Vakiomalli on erottaa pieni SubmitButton-asiakaskomponentti ja sijoittaa se form-tagien väliin.

Yksinkertainen SubmitButton-komponentti

Luokaa lähetyspainiketta varten oma asiakaskomponentti. Koska se käyttää hookia, se tarvitsee "use client"-direktiivin.

  • Lukekaa pending kutsusta useFormStatus().
  • Yhdistäkää se painikkeen disabled-attribuuttiin.
  • Vaihtakaa painikkeen teksti pending-arvon perusteella.
"use client";

import { useFormStatus } from "react-dom";

export function SubmitButton() {
  const { pending } = useFormStatus();

  return (
    <button type="submit" disabled={pending}>
      {pending ? "Saving..." : "Save"}
    </button>
  );
}

Sen yhdistäminen lomakkeeseen

Renderöikää nyt SubmitButton lomakkeen sisällä, kun lomakkeen action on Server Action. Painike tietää automaattisesti ylemmän tason lomakkeen tilan — propseja ei tarvitse välittää sille.

Ylemmän tason lomake voi säilyä Server Componentina; vain painike on asiakaskomponentti.

import { SubmitButton } from "./submit-button";
import { createPost } from "./actions";

export default function NewPostForm() {
  return (
    <form action={createPost}>
      <input name="title" required />
      <textarea name="body" required />
      <SubmitButton />
    </form>
  );
}

Server Action -puoli

pending-lippu muuttuu arvoksi true heti lomakkeen lähettämisen jälkeen ja takaisin arvoksi false, kun Server Action valmistuu. Tässä on tyypillinen aikaa vievä action (tietokantakirjoitus + välimuistin päivitys).

Merkitkää tiedosto "use server"-direktiivillä, jotta jokaista vietyä funktiota voidaan kutsua Server Actionina.

"use server";

import { revalidatePath } from "next/cache";
import { db } from "@/lib/db";

export async function createPost(formData: FormData) {
  const title = String(formData.get("title"));
  const body = String(formData.get("body"));

  await db.post.create({ data: { title, body } });

  revalidatePath("/posts");
}

Latauskuvakkeen lisääminen

Tekstin vaihtamisen lisäksi haluatte usein näyttää visuaalisen latauskuvakkeen. Renderöikää latauskuvake ehdollisesti, kun pending on true, ja pitäkää painike poissa käytöstä.

  • Pitäkää painike disabled-tilassa, jotta sitä ei voi napsauttaa uudelleen.
  • Käyttäkää aria-disabled-attribuuttia tai visuaalisesti piilotettua tekstiä saavutettavuuden varmistamiseksi.
"use client";

import { useFormStatus } from "react-dom";
import { Spinner } from "@/components/spinner";

export function SubmitButton() {
  const { pending } = useFormStatus();

  return (
    <button type="submit" disabled={pending} aria-disabled={pending}>
      {pending && <Spinner />}
      {pending ? "Submitting" : "Submit"}
    </button>
  );
}

Myös muiden kenttien poistaminen käytöstä

useFormStatus ei rajoitu painikkeisiin. Mikä tahansa lomakkeen sisällä oleva lapsikomponentti voi lukea pending-arvon ja reagoida siihen. Yleinen malli on poistaa syötekentät käytöstä lähetyksen ajaksi, jotta käyttäjä ei voi muokata tietoja kesken lähetyksen.

Muistakaa vain, että jokaisen tällaisen komponentin on oltava lomakkeen sisälle sijoitettu Client Component.

"use client";

import { useFormStatus } from "react-dom";

export function TitleField() {
  const { pending } = useFormStatus();

  return (
    <input
      name="title"
      required
      disabled={pending}
      placeholder="Post title"
    />
  );
}

Lähetettyjen tietojen tarkasteleminen

data-kenttä sisältää parhaillaan lähetettävän FormData-tiedon. Sen avulla voitte näyttää optimistisen esikatselun tallennettavasta sisällöstä – voitte esimerkiksi näyttää otsikon pyynnön käsittelyn aikana.

Varautukaa null-arvoon: data on täytetty vain, kun pending on true.

"use client";

import { useFormStatus } from "react-dom";

export function PendingPreview() {
  const { pending, data } = useFormStatus();

  if (!pending) return null;

  const title = data?.get("title")?.toString() ?? "";
  return <p>Saving \u201c{title}\u201d...</p>;
}

useFormStatus vs useTransition

Kaksi hookia seuraa käyttöliittymän odotustilaa, mutta ne ratkaisevat eri ongelmia:

  • useFormStatus – tarkoitettu erityisesti lomakkeille; lukee lähimmän ylemmän tason <form>-elementin tilan. Tilaa ei tarvitse hallita itse, mutta komponentin on sijaittava lomakkeen sisällä.
  • useTransition – yleiskäyttöinen; kutsutte toimintoa startTransition-funktion sisällä ja luette isPending-arvoa. Toimii painikkeilla, joita ei ole kääritty lomakkeeseen (esimerkiksi poistopainikkeella, joka kutsuu toimintoa onClick-käsittelijän kautta).

Kun lähetätte deklaratiivisella tavalla <form action={...}>, suosikaa useFormStatus-hookia.

Puhdas TypeScript: tilan mallintaminen

Tässä on kehyksistä riippumaton tapa hahmottaa, mitä useFormStatus palauttaa. Mallinnamme tilan rakenteen ja pienen tilakoneen, joka vastaa sitä, miten pending-arvo vaihtuu lähetyksen aikana.

Tämä toimii missä tahansa TypeScript-tuomarissa – Reactia tai palvelinta ei tarvita.

type FormStatus = {
  pending: boolean;
  method: "get" | "post" | null;
};

function simulateSubmit(): FormStatus[] {
  const timeline: FormStatus[] = [];
  timeline.push({ pending: false, method: null }); // idle
  timeline.push({ pending: true, method: "post" }); // submitting
  timeline.push({ pending: false, method: null }); // resolved
  return timeline;
}

for (const s of simulateSubmit()) {
  console.log(`pending=${s.pending} method=${s.method}`);
}

Pikatarkistus

Lisäätte useFormStatus()-hookin suoraan samaan komponenttiin, joka muodostaa <form>-elementin, ja sidotte pending-arvon lähetyspainikkeeseen. Painike ei koskaan poistu käytöstä. Miksi?

Kertaus

Opitte antamaan lomakkeille reagoivaa palautetta useFormStatus-hookin avulla:

  • Tuokaa se moduulista react-dom ja lukekaa pending-arvoa (sekä data-, method- ja action-arvoja).
  • Kutsukaa hookia aina lapsikomponentissa, joka muodostetaan <form>-elementin sisällä – tyypillisesti "use client" SubmitButton-komponentissa.
  • Yhdistäkää pending disabled-ominaisuuteen ja vaihtakaa tekstiä tai näyttäkää latauskuvake kaksoislähetysten estämiseksi.
  • Ylemmän tason lomake voi säilyä Server Component -komponenttina; vain vuorovaikutteisen lapsikomponentin tarvitsee olla client-komponentti.
  • Kun toimintoa ei ole kääritty <form>-elementtiin, käyttäkää sen sijaan useTransition-hookia.
Aloita maksutta

Opi TypeScript tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
22
Oppitunnit
88

Usein kysytyt kysymykset

Onko oppitunti ”Odotus- ja lataustilat useFormStatusilla” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppimispolun 3 oppituntia, myös oppitunnin “Odotus- ja lataustilat useFormStatusilla”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Next.js 15 -fullstack-kehitys (App Router + Server Actions)-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Odotus- ja lataustilat useFormStatusilla”?

Poistakaa painikkeet käytöstä ja näyttäkää latausilmaisimet lähetyksen aikana käyttämällä useFormStatus-hookia lomakkeen lapsikomponenteissa. Harjoittelet Next.js 15 -fullstack-kehitys (App Router + Server Actions)-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Next.js 15 -fullstack-kehitys (App Router + Server Actions)-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Odotus- ja lataustilat useFormStatusilla”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppitunnilla?

Kyllä. Jokainen Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Progressiivinen parantaminen form Action -propsilla
  2. Odotus- ja lataustilat useFormStatusilla
  3. Kenttäkohtaiset validointivirheet useActionStatella
  4. Välitön palaute useOptimisticilla
← Takaisin: Next.js 15 -fullstack-kehitys (App Router + Server Actions)