Kini nga artikulo gi-sponsor sa SurveyJS Adunay usa ka modelo sa pangisip nga gipaambit sa kadaghanan sa mga developer sa React nga wala gyud kini hisgutan nga kusog. Kana nga mga porma kanunay nga kinahanglan nga mga sangkap. Kini nagpasabut nga usa ka stack sama sa:

React Hook Form para sa lokal nga estado (minimal nga re-render, ergonomic field registration, imperative interaction). Zod para sa validation (input correctness, boundary validation, type-safe parsing). React Query para sa backend: pagsumite, pagsulay pag-usab, pag-cache, pag-sync sa server, ug uban pa.

Ug alang sa kadaghanan sa mga porma - ang imong mga screen sa pag-login, ang imong mga panid sa setting, ang imong mga modal sa CRUD - kini molihok nga maayo. Ang matag piraso nagbuhat sa iyang trabaho, limpyo ang paghimo niini, ug mahimo ka nga magpadayon sa mga bahin sa imong aplikasyon nga tinuud nga nagpalahi sa imong produkto. Apan matag karon ug unya, ang usa ka porma magsugod sa pagtigum sa mga butang sama sa visibility nga mga lagda nga nagdepende sa naunang mga tubag, o nakuha nga mga bili nga mosaka sa tulo ka field. Tingali bisan ang tibuuk nga mga panid nga kinahanglan laktawan o ipakita base sa usa ka total nga nagdagan. Gidumala nimo ang una nga kondisyon nga adunay usa ka useWatch ug usa ka inline nga sanga, nga maayo. Unya lain. Unya nakab-ot nimo ang superRefine aron ma-encode ang mga lagda sa cross-field nga dili mapahayag sa imong Zod schema sa normal nga paagi. Pagkahuman, ang lakang sa pag-navigate nagsugod sa pagtulo sa lohika sa negosyo. Sa usa ka punto, imong gitan-aw kung unsa ang imong gitukod ug nahibal-an nga ang porma dili na UI. Kini labaw pa sa usa ka proseso sa pagdesisyon, ug ang punoan sa sangkap mao ra kung diin nimo kini gitipigan. Dinhi sa akong hunahuna ang modelo sa pangisip alang sa mga porma sa React naguba, ug wala gyud kini sayup. Ang RHF + Zod stack maayo kaayo sa kung unsa kini gidisenyo. Ang isyu mao nga kita adunay kanunay nga paggamit niini lapas sa punto diin ang mga abstraction niini mohaum sa problema tungod kay ang alternatibo nanginahanglan usa ka lahi nga paagi sa paghunahuna bahin sa mga porma sa hingpit. Kini nga artikulo bahin sa kana nga alternatibo. Aron ipakita kini, magtukod kami sa eksaktong parehas nga multi-step nga porma sa makaduha:

Uban sa React Hook Form + Zod wired sa React Query para sa pagsumite, Uban sa SurveyJS, nga nagtagad sa usa ka porma ingon data - usa ka yano nga JSON schema - kaysa usa ka sangkap nga punoan.

Parehas nga kinahanglanon, parehas nga conditional logic, parehas nga tawag sa API sa katapusan. Dayon among i-mapa ang eksakto kung unsa ang mibalhin ug unsa ang nagpabilin, ug ibutang ang praktikal nga paagi sa pagdesisyon kung unsang modelo ang imong gamiton, ug kanus-a. Ang porma nga among gitukod:

Kini nga porma mogamit ug 4 ka lakang nga dagan: Lakang 1: Mga Detalye

Unang ngalan (gikinahanglan), Email (gikinahanglan, balido nga pormat).

Lakang 2: Pag-order

Presyo sa yunit, gidaghanon, Tax rate, Nakuha: Subtotal, buhis, Total.

Lakang 3: Account & Feedback

Naa kay account? (Oo/Dili) Kung Oo → username + password, gikinahanglan ang duha. Kung Dili → email nakolekta na sa lakang 1.

Rating sa katagbawan (1–5) Kung ≥ 4 → pangutana og “Unsay imong ganahan?” Kon ≤ 2 → pangutan-a ang “Unsay atong mapauswag?”

Lakang 4: Pagrepaso

Makita lang kung total >= 100 Katapusan nga pagsumite.

Dili kini sobra. Apan igo na nga ibutyag ang mga kalainan sa arkitektura. Bahin 1: Component-Driven (React Hook Form + Zod) Pag-instalar npm instalar react-hook-form zod @hookform/resolvers @tanstack/react-query

Zod Schema Magsugod kita sa eskema sa Zod, tungod kay kana kasagaran diin ang porma sa porma matukod. Para sa unang duha ka lakang — personal nga mga detalye ug order inputs — ang tanan prangka: gikinahanglang mga kuwerdas, mga numero nga adunay mga minimum, ug usa ka enum. Ang makapaikag nga bahin magsugod sa diha nga ikaw mosulay sa pagpahayag sa kondisyon nga mga lagda.

import {z} gikan sa "zod";

export const formSchema = z.object({firstName: z.string().min(1, "Kinahanglan"), email: z.string().email("Invalid email"), presyo: z.number().min(0), quantity: z.number().min(1), taxRate: z.number(), hasAccount:z.enumNo. password: z.string().optional(), katagbawan: z.number().min(1).max(5), positiveFeedback: z.string().optional(), improvementFeedback: z.string().optional(),}).superRefine((data, ctx) => {kon (data.hasAccount === "Oo") {kon (!data.username) {scode(!data.username) {s. ["username"], mensahe: "Kinahanglan" }); } if (!data.password || data.password.length < 6) { ctx.addIssue({ code: "custom", path: ["password"], message: "Min 6 characters" } }

kon (data.satisfaction >= 4 && !data.positiveFeedback) {ctx.addIssue({code: "custom", path: ["positiveFeedback"], message: "Palihug ipaambit ang imong nagustohan"}); }

kon (data.satisfaction <= 2 && !data.improvementFeedback) {ctx.addIssue({code: "custom", path:["improvementFeedback"], mensahe: "Palihug sultihi mi kung unsay angay pauswagon" }); }});

export type nga FormData = z.infer;

Matikdi nga ang username ug password gi-type isip opsyonal() bisan og kini gikinahanglan sa kondisyon tungod kay ang Zod's type-level schema naghulagway sa porma sa butang, dili ang mga lagda nga nagdumala kung ang mga field importante. Ang kinahanglanon nga kondisyon kinahanglan nga magpuyo sa sulod sa superRefine, nga modagan pagkahuman mapamatud-an ang porma ug adunay access sa tibuuk nga butang. Kana nga panagbulag dili usa ka sayup; mao ra kini ang gidesinyo sa himan: ang superRefine kung diin moadto ang cross-field logic kung dili kini mapahayag sa istruktura sa schema mismo. Ang talagsaon usab dinhi mao ang wala ipahayag niini nga schema. Wala kini konsepto sa mga panid, walay konsepto kung unsang mga field ang makita kung asa nga punto, ug walay konsepto sa nabigasyon. Kanang tanan magpuyo sa laing dapit. Porma nga Component

import {useForm, useWatch } gikan sa "react-hook-form";import {zodResolver} gikan sa "@hookform/resolvers/zod";import {useMutation} gikan sa "@tanstack/react-query";import {useState, useMemo} gikan sa "react";import {formSchema, type ang FormData}

const STEPS = ["detalye", "order", "account", "review"];

type OrderPayload = FormData & {subtotal: numero; buhis: numero; total: numero };

export function RHFMultiStepForm() {const [lakang, setStep] = useState(0);

const mutation = useMutation({ mutationFn: async (payload: OrderPayload) => { const res = maghulat sa pagkuha ("/api/mga order", { pamaagi: "POST", mga ulohan: { "Content-Type": "application/json" }, lawas: JSON.stringify(payload), }); kung (!res.ok) ilabay ang bag-ong Error("Napakyas sa pagsumite"); ibalik ang res.json(); }, });

const {rehistro, kontrol, handleSubmit, formState: {mga sayop}, } = useForm({solver: zodResolver(formSchema), defaultValues: {presyo: 0, gidaghanon: 1, taxRate: 0.1, katagbawan: 3, hasAccount: "}", }, const price = useWatch({kontrol, ngalan: "presyo" }); const quantity = useWatch({kontrol, ngalan: "gidaghanon" }); const taxRate = useWatch({kontrol, ngalan: "taxRate"}); const hasAccount = useWatch({kontrol, ngalan: "hasAccount"}); const katagbawan = useWatch({kontrol, ngalan: "katagbawan" }); const subtotal = useMemo(() => (presyo ?? 0) * (gidaghanon ?? 1), [presyo, gidaghanon]); const tax = useMemo(() => subtotal * (taxRate ?? 0), [subtotal, taxRate]); const total = useMemo(() => subtotal + buhis, [subtotal, buhis]); const onSubmit = (data: FormData) => mutation.mutate({ ...data, subtotal, buhis, total }); const showSubmit = (lakang === 2 && total <100) || (lakang === 3 && total >= 100)

ibalik (

{step === 0 && ( <> )}

{lakang === 1 && ( <>

Subtotal: {subtotal}
Tax: {tax}
Total: {total}
)}

{lakang === 2 && ( <>

{hasAccount === "Oo" && ( <> )}

{katagbawan >= 4 && (