Dan l-artikolu huwa sponsorjat minn SurveyJS Hemm mudell mentali li ħafna mill-iżviluppaturi React jaqsmu mingħajr ma qatt jiddiskutuh b'leħen għoli. Li l-formoli dejjem suppost ikunu komponenti. Dan ifisser munzell bħal:

React Hook Form għall-istat lokali (re-renders minimi, reġistrazzjoni ergonomika tal-kamp, interazzjoni imperattiva). Zod għall-validazzjoni (korrettezza tad-dħul, validazzjoni tal-konfini, parsing sigur tat-tip). Irreaġixxi Mistoqsija għal backend: sottomissjoni, provi mill-ġdid, caching, sinkronizzazzjoni tas-server, eċċ.

U għall-maġġoranza vasta tal-formoli — l-iskrins tal-login tiegħek, il-paġni tas-settings tiegħek, il-modals CRUD tiegħek — dan jaħdem tajjeb ħafna. Kull biċċa tagħmel xogħolha, huma jikkomponu b'mod nadif, u tista 'timxi fuq il-partijiet tal-applikazzjoni tiegħek li fil-fatt jiddifferenzjaw il-prodott tiegħek. Iżda kull darba, formola tibda takkumula affarijiet bħal regoli tal-viżibilità li jiddependu fuq tweġibiet preċedenti, jew valuri derivati ​​li jgħaddu minn tliet oqsma. Forsi anke paġni sħaħ li għandhom jinqabżu jew jintwerew ibbażati fuq total kurrenti. Int timmaniġġja l-ewwel kondizzjonali b'useWatch u fergħa inline, li hija tajba. Imbagħad ieħor. Imbagħad int qed tilħaq għal superRefine biex tikkodifika regoli bejn il-kampijiet li l-iskema Zod tiegħek ma tistax tesprimi bil-mod normali. Imbagħad, in-navigazzjoni tal-pass tibda tnixxi l-loġika tan-negozju. F'xi punt, tħares lejn dak li bnejt u tirrealizza li l-formola m'għadhiex verament UI. Huwa aktar proċess ta 'deċiżjoni, u s-siġra tal-komponenti hija eżatt fejn ġara li taħżenha. Dan huwa fejn naħseb li l-mudell mentali għall-formoli f'React jkisser, u huwa verament tort ta 'ħadd. Il-munzell RHF + Zod huwa eċċellenti għal dak li kien iddisinjat għalih. Il-kwistjoni hija li għandna t-tendenza li nibqgħu nużawha wara l-punt fejn l-astrazzjonijiet tagħha jaqblu mal-problema minħabba li l-alternattiva teħtieġ mod differenti ta 'ħsieb dwar il-forom għal kollox. Dan l-artikolu huwa dwar dik l-alternattiva. Biex nuru dan, aħna ser nibnu l-istess formola f'diversi stadji eżatt darbtejn:

Bil-Formola React Hook + Zod bil-fili biex React Query għas-sottomissjoni, Ma' SurveyJS, li jittratta formola bħala data — skema JSON sempliċi — aktar milli siġra tal-komponenti.

L-istess rekwiżiti, l-istess loġika kondizzjonali, l-istess sejħa API fl-aħħar. Imbagħad aħna nimmappaw eżattament dak li ċaqlaq u dak li baqa’, u nistabbilixxu mod prattiku biex niddeċiedu liema mudell għandek tuża, u meta. Il-formola li qed nibnu:

Din il-formola se tuża fluss f'4 passi: Pass 1: Dettalji

L-isem (meħtieġa), Email (meħtieġa, format validu).

Pass 2: Ordna

Prezz unitarju, Kwantità, Rata tat-taxxa, Derivat: Subtotal, Taxxa, Total.

Pass 3: Kont u Feedback

Għandek kont? (Iva/Le) Jekk Iva → username + password, it-tnejn meħtieġa. Jekk Le → email diġà miġbura fil-pass 1.

Klassifikazzjoni ta' sodisfazzjon (1–5) Jekk ≥ 4 → staqsi “X’għoġbok?” Jekk ≤ 2 → staqsi “X’nistgħu ntejbu?”

Pass 4: Reviżjoni

Jidher biss jekk totali >= 100 Sottomissjoni finali.

Dan mhux estrem. Iżda huwa biżżejjed li tesponi d-differenzi arkitettoniċi. Parti 1: Immexxi mill-Komponent (Formola ta' Reazzjoni tal-Hook + Zod) Installazzjoni npm install react-hook-form zod @hookform/resolvers @tanstack/react-query

Skema Zod Ejja nibdew bl-iskema Zod, għaliex normalment huwa fejn il-forma tal-forma tiġi stabbilita. Għall-ewwel żewġ passi — dettalji personali u inputs tal-ordnijiet — kollox huwa sempliċi: kordi meħtieġa, numri b'minimi, u enum. Il-parti interessanti tibda meta tipprova tesprimi r-regoli kundizzjonali.

importazzjoni { z } minn "zod";

export const formSchema = z.object({ firstName: z.string().min(1, "Meħtieġa"), email: z.string().email("Invalid email"), price: z.number().min(0), kwantità: z.number().min(1), taxRate: z.number(), hasAccount: "["]), enname: z.string().optional(), password: z.string().optional(), sodisfazzjon: z.number().min(1).max(5), positiveFeedback: z.string().optional(), improvementFeedback: z.string().optional(),}).superRefine((data, ctx) => {jekk (data, ctx) => {jekk (data) . ctx.addIssue({ code: "custom", path: ["username"], message: "Meħtieġ" }); } if (!data.password || data.password.length < 6) { ctx.addIssue({ code: "custom", path: ["password"], messaġġ: "Min 6 karattri}"});

jekk (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ code: "custom", path: ["positiveFeedback"], message: "Jekk jogħġbok aqsam dak li għoġobt" }); }

jekk (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue ({ kodiċi: "custom", mogħdija:["improvementFeedback"], message: "Jekk jogħġbok għidilna x'għandna ntejbu"}); }});

tip ta' esportazzjoni FormData = z.infer;

Innota li l-isem tal-utent u l-password huma ttajpjati bħala fakultattivi () anki jekk huma meħtieġa kondizzjonalment minħabba li l-iskema tal-livell tat-tip ta 'Zod tiddeskrivi l-għamla tal-oġġett, mhux ir-regoli li jirregolaw meta l-oqsma huma importanti. Ir-rekwiżit kondizzjonali għandu jgħix ġewwa superRefine, li jibda wara li l-forma tiġi vvalidata u jkollha aċċess għall-oġġett sħiħ. Dik is-separazzjoni mhix difett; huwa biss għalxiex l-għodda hija ddisinjata: superRefine hija fejn tmur il-loġika cross-field meta ma tistax tiġi espressa fl-istruttura tal-iskema nnifisha. Dak li huwa wkoll notevoli hawnhekk huwa dak li din l-iskema ma tesprimix. M'għandha l-ebda kunċett ta 'paġni, l-ebda kunċett ta' liema oqsma huma viżibbli f'liema punt, u l-ebda kunċett ta 'navigazzjoni. Dan kollu se jgħix x'imkien ieħor. Komponent tal-Formola

importazzjoni { useForm, useWatch } minn "react-hook-form";importazzjoni { zodResolver } minn "@hookform/resolvers/zod";importazzjoni { useMutation } minn "@tanstack/react-query";importazzjoni {useState, useMemo } minn "react";import {formSchema, tip "Form./resolver"};

const STEPS = ["dettalji", "ordni", "kont", "reviżjoni"];

tip OrderPayload = FormData & { subtotal: numru; taxxa: numru; total: numru };

funzjoni ta' esportazzjoni RHFMultiStepForm () { const [step, setStep] = useState (0);

const mutation = useMutation ({ mutationFn: async (tagħbija: OrderPayload) => { const res = stenna fetch ("/api/ordnijiet", { metodu: "POST", headers: { "Content-Type": "application/json" }, korp: JSON.stringify (tagħbija), }); if (!res.ok) throw Error ġdid ("Falla milli tissottometti"); ritorn res.json (); }, });

const { register, control, handleSubmit, formState: { żbalji }, } = useForm({ resolver: zodResolver(formSchema), defaultValues: { prezz: 0, kwantità: 1, taxRate: 0.1, sodisfazzjon: 3, hasAccount: "Le", }, }); const price = useWatch({ kontroll, isem: "prezz" }); const kwantità = useWatch ({ kontroll, isem: "kwantità" }); const taxRate = useWatch({ kontroll, isem: "taxRate" }); const hasAccount = useWatch ({ kontroll, isem: "hasAccount" }); const sodisfazzjon = useWatch({ kontroll, isem: "sodisfazzjon" }); const subtotal = useMemo(() => (prezz ?? 0) * (kwantità ?? 1), [prezz, kwantità]); const tax = useMemo(() => subtotal * (taxRate ?? 0), [subtotal, taxRate]); const total = useMemo(() => subtotal + taxxa, [subtotal, taxxa]); const onSubmit = (data: FormData) => mutation.mutate({ ...data, subtotal, tax, total }); const showSubmit = (pass === 2 && totali < 100) || (pass === 3 && total >= 100)

return (

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

{pass === 1 && ( <>

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

{pass === 2 && ( <>

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

{sodisfazzjon >= 4 && (