Ity lahatsoratra ity dia tohanan'ny SurveyJS Misy modely ara-tsaina zarain'ny ankamaroan'ny mpamorona React nefa tsy miresaka momba izany. Ireo endrika ireo dia heverina ho singa foana. Izany dia midika hoe stack toy ny:

React Hook Form ho an'ny fanjakana eo an-toerana (famerenana kely indrindra, fisoratana anarana amin'ny saha ergonomika, fifandraisana tsy maintsy atao). Zod ho an'ny fanamarinana (fahamarinana fampidirana, fanamarinana sisintany, fanasokajiana azo antoka). React Query ho an'ny backend: fandefasana, andrana indray, caching, sync server, sns.

Ary ho an'ny ankamaroan'ny endrika - ny efijery fidiranao, ny pejin'ny fanovanao, ny CRUD modals anao - tena miasa tsara izany. Ny singa tsirairay dia manao ny asany, mamorona madio izy ireo, ary afaka mandroso amin'ny ampahany amin'ny fampiharana anao izay tena mampiavaka ny vokatrao ianao. Saingy indraindray, ny endrika iray dia manomboka manangona zavatra toy ny fitsipiky ny fahitana izay miankina amin'ny valiny teo aloha, na ny soatoavina azo avy amin'ny sanda telo. Mety ho pejy iray manontolo mihitsy aza izay tokony hatsipy na aseho mifototra amin'ny totalin'ny mihazakazaka. Mitantana ny fepetra voalohany ianao amin'ny fampiasana Watch sy sampana inline, izay tsara. Dia hafa. Avy eo ianao dia tonga any amin'ny superRefine mba hanisy fehezan-dalàna mifanandrify izay tsy azon'ny schema Zod aseho amin'ny fomba mahazatra. Avy eo, manomboka mitete ny lojikan'ny fandraharahana ny fitetezana dingana. Amin'ny fotoana iray, mijery izay naorinao ianao ary mahatsapa fa tsy tena UI intsony ilay endrika. Fanapahan-kevitra bebe kokoa izany, ary ny hazo singa no toerana nitehirizanao azy. Eto no heveriko fa rava ny maodely ara-tsaina ho an'ny endrika ao amin'ny React, ary tena tsy misy diso mihitsy. Ny stack RHF + Zod dia tena tsara amin'ny nanaovana azy. Ny olana dia ny fampiasana azy hatrany hatrany amin'ny teboka izay mifanaraka amin'ny olana ny abstractions satria ny safidy dia mitaky fomba fisainana hafa momba ny endrika. Ity lahatsoratra ity dia momba an'io safidy io. Mba hampisehoana izany dia hanangana endrika mitovy dingana indroa isika:

Miaraka amin'ny React Hook Form + Zod mifandray amin'ny React Query amin'ny fandefasana, Miaraka amin'ny SurveyJS, izay mandray endrika ho angon-drakitra - schema JSON tsotra - fa tsy hazo singa.

Ny fepetra mitovy, ny lojika misy fepetra mitovy, ny antso API mitovy amin'ny farany. Avy eo isika dia hanao sarintany marina izay nifindra sy izay nijanona, ary mametraka fomba azo ampiharina hanapahana izay modely tokony hampiasainao, ary rahoviana. Ny endrika amboarinay:

Ity endrika ity dia hampiasa fikoriana 4 dingana: Dingana 1: Details

Anarana voalohany (takina), Email (takina, endrika manan-kery).

Dingana 2: baiko

Vidiny iray, Isan'ny, tahan'ny hetra, Nalaina: Subtotal, hetra, Total.

Dingana 3: Account & Feedback

Manana kaonty ve ianao? (Eny/Tsia) Raha Eny → solonanarana + tenimiafina dia samy ilaina. Raha Tsia → mailaka efa voaangona ao amin'ny dingana 1.

Naoty fahafaham-po (1–5) Raha ≥ 4 → dia anontanio hoe “Inona no tianao?” Raha ≤ 2 → manontany hoe “Inona no azo hatsaraina?”

Dingana 4: Famerenana

Miseho ihany raha total >= 100 Fandefasana farany.

Tsy tafahoatra izany. Saingy ampy ny mampiharihary ny fahasamihafana ara-javakanto. Fizarana 1: Entin'ny singa (React Hook Form + Zod) Fametrahana npm mametraka react-hook-form zod @hookform/resolvers @tanstack/react-query

Zod Schema Andeha isika hanomboka amin'ny skema Zod, satria matetika no misy ny endriky ny endrika. Ho an'ny dingana roa voalohany - ny antsipiriany manokana sy ny fampidirana baiko - ny zava-drehetra dia tsotra: tady ilaina, isa misy kely indrindra ary enum. Ny ampahany mahaliana dia manomboka rehefa manandrana maneho ny fitsipika misy fepetra ianao.

manafatra { z } avy amin'ny "zod";

export const formSchema = z.object({ firstName: z.string().min(1, "Required"), email: z.string().mail("Invalid invalid"), vidiny: z.number().min(0), quantity: z.number().min(1), taxRate: z.number(), hasAccount:z.enum"(z.enum) tenimiafina: z.string().optional(), fahafaham-po: z.number().min(1).max(5), positiveFeedback: z.string().optional(), improvementFeedback: z.string().optional(),}).superRefine((data. ["username"], hafatra: "Ilaina" }); } raha (!data.password || data.password.length < 6) { ctx.addIssue({ code: "custom", lalana: ["password"], message: "Min 6 characters" } }

raha (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ code: "custom", lalana: ["positiveFeedback"], message: "Mba zarao izay tianao" }); }

raha (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue({ code: "custom", lalana:["improvementFeedback"], hafatra: "Mba lazao anay izay tokony hohatsaraina" }); }});

karazana fanondranana FormData = z.infer;

Mariho fa ny solon'anarana sy ny tenimiafina dia soratana ho safidy () na dia takiana amin'ny fepetra aza izy ireo satria ny skema karazana karazana Zod dia mamaritra ny endriky ny zavatra, fa tsy ny fitsipika mifehy ny sehatra. Ny fepetra takiana dia tsy maintsy miaina ao anatin'ny superRefine, izay mandeha aorian'ny fanamarinana ny endrika ary mahazo ny zavatra feno. Tsy kilema izany fisarahana izany; io ihany no natao ho an'ny fitaovana: ny superRefine dia ny fandehan'ny lojika cross-field rehefa tsy azo aseho ao amin'ny rafitra schema mihitsy. Ny zava-dehibe ihany koa eto dia ny tsy asehon'ity tetika ity. Tsy manana foto-kevitra momba ny pejy izy io, tsy misy foto-kevitra momba ny saha hita amin'ny fotoana inona, ary tsy misy hevitra momba ny fitetezana. Izany rehetra izany dia hipetraka any an-kafa. Form Component

manafatra { useForm, useWatch } avy amin'ny "react-hook-form"; import {zodResolver } avy amin'ny "@hookform/resolvers/zod";import {useMutation} avy amin'ny "@tanstack/react-query";import {useState, useMemo} avy amin'ny "react";import {formSchema, type FormData}

const STEPS = ["details", "order", "kaonty", "review"];

karazana OrderPayload = FormData & { subtotal: isa; hetra: isa; total: isa };

asa fanondranana RHFMultiStepForm() {const [dingana, setStep] = useState(0);

const mutation = useMutation({ mutationFn: async (vola: OrderPayload) => { const res = miandry fetch("/api/orders", { fomba: "POST", lohapejy: { "Content-Type": "application/json" }, vatana: JSON.stringify(payload), }); raha (!res.ok) manipy Error vaovao("Tsy nahomby"); miverina res.json(); }, });

const { Register, Control, HandSubmit, formState: { errors }, } = useForm({solver: zodResolver(formSchema), defaultValues: {prix: 0, quantity: 1, taxRate: 0.1, satisfaction: 3, hasAccount: "}", }, } vidiny const = useWatch({ control, anarana: "vidiny" }); const quantity = useWatch({ control, anarana: "habeny" }); const taxRate = useWatch({ control, anarana: "taxRate" }); const hasAccount = useWatch({ control, name: "hasAccount" }); const satisfaction = useWatch({ control, name: "satisfaction" }); const subtotal = useMemo(() => (vidiny ?? 0) * (beny ?? 1), [vidiny, isa]); const tax = useMemo(() => subtotal * (taxRate ?? 0), [subtotal, taxRate]); const total = useMemo(() => subtotal + hetra, [subtotal, hetra]); const onSubmit = (data: FormData) => mutation.mutate({...data, subtotal, hetra, total }); const showSubmit = (dingana === 2 && total < 100) || (dingana === 3 && total >= 100)

miverina (

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

{dingana === 1 && ( <>

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

{dingana === 2 && ( <>

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

{fahafaham-po >= 4 && (