Artikulu hau SurveyJS-ek babestutakoa da React-eko garatzaile gehienek partekatzen duten eredu mental bat dago inoiz ozen eztabaidatu gabe. Formak beti osagai izan behar direla. Honek honelako pila bat esan nahi du:

React Hook formularioa tokiko estaturako (errendaketa minimoak, eremu ergonomikoa erregistratzea, interakzio ezinbestekoa). Zod baliozkotzeko (sarreraren zuzentasuna, muga-balioztapena, mota seguruaren analisia). React Query backend-erako: bidalketa, berriro saiakerak, cachean gordetzea, zerbitzariaren sinkronizazioa eta abar.

Eta inprimaki gehienentzat - zure saio-hasierako pantailak, zure ezarpen-orriak, zure CRUD modalitateak - oso ondo funtzionatzen du. Pieza bakoitzak bere lana egiten du, garbi konposatzen dute, eta zure produktua benetan bereizten duten aplikazioaren ataletara pasa dezakezu. Baina noizean behin, inprimaki bat lehenagoko erantzunen araberako ikusgarritasun-arauak edo hiru eremutan zehar jauzi egiten diren balio eratorriak bezalako gauzak pilatzen hasten dira. Baliteke orri osoak ere saltatu edo erakutsi beharko liratekeen guztirako batean oinarrituta. UseWatch eta inline adar batekin kudeatzen duzu lehen baldintza, eta hori ondo dago. Gero beste bat. Orduan superRefine-ra iristen ari zara zure Zod eskemak modu normalean adierazi ezin dituen eremuen arteko arauak kodetzeko. Ondoren, urratsen nabigazioa negozio-logika isurtzen hasten da. Noizbait, eraiki duzunari begiratzen diozu eta konturatzen zara inprimakia jada ez dela benetan UI. Erabaki prozesu bat baino gehiago da, eta osagaien zuhaitza gorde zenuen tokian dago. Hemen uste dut React-en formen eredu mentala apurtzen dela, eta benetan ez da inoren errua. RHF + Zod pila bikaina da diseinatu zenerako. Kontua da erabiltzen jarraitu ohi dugula bere abstrakzioak arazoarekin bat datozen puntutik igarota, alternatibak formei buruz guztiz pentsatzeko beste modu bat eskatzen duelako. Artikulu hau alternatiba horri buruzkoa da. Hau erakusteko, urrats anitzeko inprimaki bera eraikiko dugu bi aldiz:

React Hook formularioa + Zod-ekin bidaltzeko React Query-ra kabletuta, SurveyJS-rekin, inprimaki bat datu gisa tratatzen du —JSON eskema soil bat— osagaien zuhaitz bat baino.

Baldintza berdinak, baldintzazko logika bera, amaieran API dei bera. Ondoren, zer mugitu den eta zer geratu den mapatuko dugu, eta zein eredu erabili behar duzun eta noiz erabakitzeko modu praktiko bat ezarriko dugu. Eraikitzen ari garen formularioa:

Inprimaki honek 4 urratseko fluxua erabiliko du: 1. urratsa: Xehetasunak

Izena (beharrezkoa), Posta elektronikoa (beharrezkoa, baliozko formatua).

2. urratsa: ordena

Unitatearen prezioa, Kantitatea, Zerga tasa, Eratorria: Azpi-totala, Zerga, Guztira.

3. urratsa: kontua eta iritzia

Ba al duzu konturik? (Bai/Ez) Bai bada → erabiltzaile izena + pasahitza, biak beharrezkoak. Ez bada → 1. urratsean dagoeneko bildutako mezu elektronikoa.

Asebetetze balorazioa (1-5) ≥ 4 bada → galdetu "Zer gustatu zaizu?" ≤ 2 bada → galdetu "Zer hobetu dezakegu?"

4. urratsa: berrikuspena

Guztira >= 100 bada bakarrik agertzen da Azken bidalketa.

Hau ez da muturrekoa. Baina nahikoa da ezberdintasun arkitektonikoak agerian uztea. 1. zatia: osagaiek gidatutakoa (erreakzionatzeko amua + zod) Instalazioa npm instalatu react-hook-form zod @hookform/resolvers @tanstack/react-query

Zod eskema Has gaitezen Zod eskemarekin, normalean hor finkatzen baita formaren forma. Lehenengo bi urratsetarako — xehetasun pertsonalak eta eskaeraren sarrerak — dena erraza da: beharrezko kateak, gutxieneko zenbakiak eta enumerazioa. Zati interesgarria baldintzapeko arauak adierazten saiatzen zarenean hasten da.

inportatu {z } "zod"-tik;

export const formSchema = z.object({ firstName: z.string().min(1, "Derrigorrezkoa"), posta elektronikoa: z.string().email("E-posta baliogabea"), prezioa: z.number().min(0), kantitatea: z.number().min(1), taxRate: z.number(), hasAccount(No"]), hasAccount: "Y:" z.string().optional(), pasahitza: z.string().optional(), gogobetetasuna: z.number().min(1).max(5), positiveFeedback: z.string().optional(), improvementFeedback: z.string().optional(),}).superRefine((datuak, ctx) => { if (datuak) === "Yes Account. ctx.addIssue({ kodea: "pertsonalizatua", bidea: ["erabiltzaile-izena"], mezua: "Derrigorrezkoa" }); } if (!data.password || data.password.length < 6) { ctx.addIssue({ kodea: "personalizatu", bidea: ["pasahitza"], mezua: "Gutxienez 6 karaktere}"});

if (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue ({ kodea: "personalizatu", bidea: ["positiveFeedback"], mezua: "Mesedez, partekatu gustatu zaizuna" }); }

bada (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue ({ kodea: "pertsonalizatua", bidea:["improvementFeedback"], mezua: "Mesedez, esaiguzu zer hobetu behar dugun"}); }});

esportatu mota FormData = z.infer;

Kontuan izan erabiltzaile-izena eta pasahitza aukerako() gisa idazten direla, nahiz eta baldintzapean beharrezkoak diren, Zod-en mota-mailako eskemak objektuaren forma deskribatzen duelako, ez eremuek garrantzia dutenean arautzen duten arauak. Baldintza-eskakizunak superRefine barruan bizi behar du, forma balioztatu ondoren exekutatzen dena eta objektu osorako sarbidea duen. Banaketa hori ez da akats bat; tresna hori zertarako diseinatuta dago: superRefine eremuen arteko logika nora doa eskema-egituran bertan adierazi ezin denean. Hemen ere nabarmentzen dena eskema honek adierazten ez duena da. Ez du orrialdeen kontzepturik, ez dago zein eremutan ikusgai dagoen kontzepturik eta ez du nabigazio kontzepturik. Hori guztia beste nonbait biziko da. Inprimakiaren osagaia

inportatu { useForm, useWatch } "react-hook-form"-tik; inportatu { zodResolver } "@hookform/resolvers/zod"-tik; inportatu { useMutation } "@tanstack/react-query"-tik; inportatu { useState, useMemo } "react"-tik; inportatu { formSchema, "FormDataschema" motatik;

const STEPS = ["xehetasunak", "eskatu", "kontua", "berrikuspena"];

idatzi OrderPayload = FormData & { azpitotala: zenbakia; zerga: zenbakia; guztira: zenbakia };

esportatu funtzioa RHFMultiStepForm () { const [step, setStep] = useState (0);

const mutation = erabiliMutazioa({ mutationFn: async (karga: OrderPayload) => { const res = itxaron eskura ("/api/aginduak", { metodoa: "POST", goiburuak: { "Content-Type": "application/json" }, gorputza: JSON.stringify (karga erabilgarria), }); if (!res.ok) throw new Error("Huts egin du bidaltzean"); itzuli res.json(); }, });

const { register, control, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver(formSchema), defaultValues: { prezioa: 0, kantitatea: 1, taxRate: 0.1, gogobetetasuna: 3, hasAccount: "Ez", }, }); konst prezioa = useWatch({ kontrola, izena: "prezioa" }); konst kantitatea = useWatch ({kontrola, izena: "kantitatea"}); const taxTasa = useWatch({kontrola, izena: "taxTasa"}); const daukaKontua = erabiliIkusi({ kontrola, izena: "kontua dauka"}); const satisfation = useWatch({ kontrola, izena: "satisfaction" }); const subtotal = useMemo(() => (prezioa ?? 0) * (kantitatea ?? 1), [prezioa, kantitatea]); const tax = useMemo (() => azpi-total * (zerga-tasa ?? 0), [azpi-totala, zerga-tasa]); const total = useMemo(() => azpitotala + zerga, [azpitotal, zerga]); const onSubmit = (datuak: FormData) => mutation.mutate({ ...datuak, azpi-totala, zerga, guztira }); const showSubmit = (pausoa === 2 && guztira < 100) || (urrats === 3 && guztira >= 100)

itzuli (

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

{pausoa === 1 && ( <> : {aukeraAs egia. value="0.05">%5

Azpi-totala: {subtotal}
Zerga: {tax}
Guztira: {total}
)}

{step === 2 && ( <>

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

{asebetetasuna >= 4 && (