Ev gotar ji hêla SurveyJS ve hatî piştgirî kirin Modelek derûnî heye ku piraniya pêşdebirên React bêyî ku bi dengekî bilind nîqaş bikin parve dikin. Ew form her gav tê guman kirin ku bibin pêkhate. Ev tê wateya stûnek mîna:

Forma React Hook ji bo dewleta herêmî (ji nû vesazkirina hindiktirîn, qeydkirina zeviyê ergonomîk, danûstendina mecbûrî). Zod ji bo erêkirinê (rastiya têketinê, erêkirina sînor, parsek-ewle ya tîpê). React Query ji bo paşîn: radestkirin, ji nû ve ceribandin, caching, hevdemkirina serverê, û hwd.

Û ji bo pirraniya formên - ekranên têketina we, rûpelên mîhengên we, modalên weya CRUD - ev bi rastî baş dixebite. Her perçe karê xwe dike, ew bi paqijî çêdikin, û hûn dikarin berbi beşên serîlêdana xwe yên ku bi rastî hilberê we cûda dikin biçin. Lê her carê, formek dest bi berhevkirina tiştan dike mîna qaîdeyên xuyangiyê yên ku bi bersivên berê ve girêdayî ne, an jî nirxên jêhatî yên ku di sê qadan de derbas dibin. Dibe ku tewra rûpelên ku divê werin paşxistin an jî li ser bingeha tevheviyek xebitandinê bêne xuyang kirin. Hûn şerta yekem bi useWatch û şaxek hundurîn re mijûl dibin, ku baş e. Piştre din. Dûv re hûn digihîjin superRefine da ku qaîdeyên xaçerê yên ku şemaya Zod-a we nekare bi rengek normal eşkere bike kod bike. Dûv re, navîgasyon gav dest bi mentiqê karsaziyê dike. Di hin xalan de, hûn li tiştê ku we çêkiriye dinêrin û pê dihesin ku form êdî bi rastî ne UI ye. Ew bêtir pêvajoyek biryarê ye, û dara pêkhateyê tenê cihê ku we lê hilanîn e. Li vir ez difikirim ku modela derûnî ya formên di React de têk diçe, û ew bi rastî ne sûcê kesî ye. Stack RHF + Zod di tiştê ku ji bo wê hatî çêkirin de pir xweş e. Pirsgirêk ev e ku em mêl dikin ku wê bikar bînin ji xala ku abstraksyonên wê bi pirsgirêkê re hevrû dibin ji ber ku alternatîf bi tevahî şêwazek ramana cûda hewce dike. Ev gotar li ser wê alternatîf e. Ji bo ku vê yekê nîşan bidin, em ê heman forma pir-gavekî du caran ava bikin:

Bi Forma React Hook + Zod re ji bo radestkirinê ji bo React Query ve girêdayî ye, Bi SurveyJS re, ku formek wekî daneyê dihesibîne - şemayek JSON a hêsan - li şûna darek pêkhatî.

Heman hewcedarî, heman mantiqa şertî, heman banga API-ê di dawiyê de. Dûv re em ê tam nexşeyê bikin ka çi bar kiriye û çi maye, û rêyek pratîkî destnîşan bikin ku hûn biryar bidin ka hûn kîjan modelê û kengê bikar bînin. Forma ku em ava dikin:

Ev form dê herikîna 4-gavekî bikar bîne: Gav 1: Details

Navê (pêdivî), E-name (pêdivî, forma derbasdar).

Gav 2: Siparîş bike

Buhayê yekîneyê, Hejmar, Rêjeya bacê, Derketî: Bi tevahî, Bac, Total.

Gav 3: Hesab & Bersiv

Hesabê te heye? (Belê/Na) Ger Erê → navê bikarhêner + şîfre, her du jî hewce ne. Ger Na → e-name jixwe di gava 1-ê de hatî berhev kirin.

Rêjeya razîbûnê (1–5) Ger ≥ 4 → bipirsin "Te çi hez kir?" Ger ≤ 2 → bipirsin "Em dikarin çi çêtir bikin?"

Gav 4: Vekolîn

Tenê heke bi tevahî >= 100 xuya bibe radestkirina dawî.

Ev ne tundî ye. Lê ji bo eşkerekirina cûdahiyên mîmarî bes e. Beş 1: Pêkhatî-Driven (React Hook Form + Zod) Sazkirin npm saz bike react-hook-form zod @hookform/resolvers @tanstack/react-query

Zod Schema Ka em bi şemaya Zod dest pê bikin, ji ber ku bi gelemperî şeklê formê li wir ava dibe. Ji bo her du gavên pêşîn - hûrguliyên kesane û têketinên fermanê - her tişt rasterast e: rêzikên pêwîst, hejmarên bi hindiktirîn, û hejmarek. Beşa balkêş gava ku hûn hewl didin ku qaîdeyên şertî îfade bikin dest pê dike.

import { z } ji "zod";

hinardekirin z.string()optional(), şîfre: z.string().optional(), razîbûn: z.number().min(1).max(5),positiveFeedback: z.string().optional(), çêtirkirinaFeedback: z.string().optional(),}).superRefine((data, ifesda) = "{Afsxta)=ha"> (!data.username) { ctx.addIssue({kod: "custom", rê: ["username"], message: "Required" } } if (!data.password || data.password.length < 6) { ctx.addIssue({cod: "password", path:"}); }

if (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ kod: "custom", rê: ["Feedback"], peyam: "Ji kerema xwe tiştê ku te eciband parve bike" }); }

if (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue({ kod: "custom", rê:["improvementFeedback"], peyam: "Ji kerema xwe ji me re bêje ka em çi çêtir bikin" }); }});

cureyê hinardekirinê FormData = z.infer;

Bala xwe bidinê ku navê bikarhêner û şîfreyê wekî vebijarkî () têne nivîsandin, her çend ew bi şertî hewce ne ji ber ku şemaya asta tîpê ya Zod şeklê objektê vedibêje, ne qaîdeyên ku dema zevî girîng dibin destnîşan dike. Pêdivî ye ku pêdivî ye ku di hundurê superRefine de bijî, ku piştî ku şekil were pejirandin dimeşe û bigihîje tişta tevahî. Ew veqetandin ne xeletiyek e; ew tenê ya ku amûr ji bo hatî sêwirandin ev e: superRefine ew e ku mentiqê zevî li ku derê diçe gava ku ew nekare di avahiya şema bixwe de were diyar kirin. Ya ku li vir jî balkêş e ev e ku ev şema çi îfade nake. Têgeha wê ya rûpelan tune ye, têgehek ku li kîjan xalê têne xuyang kirin, û têgîna navîgasyonê tune. Hemî wê dê li cîhek din bijîn. Form Component

import { useForm, useWatch } ji "react-hook-form";import {zodResolver } ji "@hookform/resolvers/zod";import {useMutation } ji "@tanstack/react-query";import {useState, useMemo} ji "react";import type {formSche;

const STEPS = ["detay", "ferman", "hesab", "review"];

binivîse OrderPayload = FormData & { subtotal: hejmar; bac: hejmar; gişt: hejmar };

fonksiyona hinardekirinê RHFMultiStepForm() {const [gav, setStep] = useState(0);

const mutation = useMutation({ mutationFn: async (barkirin: OrderPayload) => { const res = li benda wergirtinê ("/api/orders", { rêbaz: "POST", sernivîs: { "Content-Type": "sepan/json" }, laş: JSON.stringify(payload), }); heke (!res.ok) xeletiyek nû bavêje ("Serkeftin nehat şandin"); vegera res.json(); }, });

const {qeyd, kontrol, handleSubmit, formState: {çewtiyên }, } = useForm({çareser: zodResolver(formSchema), defaultValues: {biha: 0, hejmar: 1, Rêjeya bacê: 0.1, razîbûn: 3, hassab: "Na");} const price = useWatch ({kontrol, nav: "biha" }); const quantity = useWatch({kontrol, nav: "quantity" }); const taxRate = useWatch({kontrol, nav: "Rêjeya bacê" }); const hasAccount = useWatch({kontrol, nav: "hasAccount" }); const satisfaction = useWatch({kontrol, nav: "r'azîbûn" }); const subtotal = useMemo(() => (biha ?? 0) * (hejmar ?? 1), [biha, hejmar]); baca const = useMemo(() => binerd * (Rêjeya bacê ?? 0), [bijmarî, Rêjeya bacê]); const total = useMemo(() => binerd + bac, [bingiştî, bac]); const onSubmit = (dane: FormData) => mutation.mutate({ ...dane, binavber, bac, tevde }); const showSubmit = (gav === 2 && gişt < 100) || (gav === 3 && bi tevahî >= 100)

vegere (

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

{gav === 1 && ( <> 5%

Bingiştî: {subtotal}
Bac: {tax}
Tevahiya: {total}
)}

{step === 2 && ( <>

{hasAccount === "Erê" && ( <> )}

{r'azîbûn >= 4 && (