Atik sa a se yon patwone pa SurveyJS Gen yon modèl mantal pifò devlopè React pataje san yo pa janm diskite sou li byen fò. Fòm sa yo toujou sipoze konpozan. Sa vle di yon pil tankou:
Fòm React Hook pou eta lokal (minim re-rann, enskripsyon jaden ergonomic, entèraksyon enperatif). Zod pou validation (correct antre, validation fwontyè, tip-safe parsing). Reyaji Rekèt pou backend: soumèt, reesye, kachèt, senkronizasyon sèvè, ak sou sa.
Ak pou vas majorite fòm yo - ekran login ou yo, paj paramèt ou yo, modal CRUD ou yo - sa a travay vrèman byen. Chak moso fè travay li, yo konpoze pwòp, epi ou ka deplase sou pati yo nan aplikasyon w lan ki aktyèlman diferansye pwodwi ou. Men, chak fwa yon ti tan, yon fòm kòmanse akimile bagay tankou règ vizibilite ki depann de repons pi bonè, oswa valè sòti ki kaskad nan twa jaden. Petèt menm paj tout antye ki ta dwe sote oswa montre ki baze sou yon total kouri. Ou okipe premye kondisyonèl la ak yon useWatch ak yon branch inline, ki se amann. Lè sa a, yon lòt. Lè sa a, w ap rive jwenn superRefine pou kode règ kwa-champ ke chema Zod ou a pa ka eksprime nan fason nòmal la. Lè sa a, navigasyon etap kòmanse koule lojik biznis. Nan kèk pwen, ou gade nan sa ou te bati epi reyalize ke fòm nan pa reyèlman UI ankò. Li plis nan yon pwosesis desizyon, ak pye bwa a eleman se jis kote ou te rive estoke li. Sa a se kote mwen panse ke modèl mantal la pou fòm nan React kraze, epi li vrèman pa fòt pèsonn. Pile RHF + Zod la ekselan nan sa li te fèt pou. Pwoblèm lan se ke nou gen tandans kontinye sèvi ak li pase pwen kote abstraksyon li yo matche ak pwoblèm nan paske altènatif la mande pou yon fason diferan pou panse sou fòm antyèman. Atik sa a se sou altènatif sa a. Pou montre sa a, nou pral bati egzak menm fòm milti-etap de fwa:
Avèk React Hook Form + Zod branche pou React Query pou soumèt, Avèk SurveyJS, ki trete yon fòm kòm done - yon senp chema JSON - olye ke yon pye bwa eleman.
Menm kondisyon, menm lojik kondisyonèl, menm apèl API nan fen an. Lè sa a, nou pral kat egzakteman sa ki deplase ak sa ki rete, epi mete deyò yon fason pratik yo deside ki modèl ou ta dwe itilize, ak ki lè. Fòm nap konstwi a:
Fòm sa a pral itilize yon koule 4 etap: Etap 1: Detay yo
Premye non (obligatwa), Imèl (obligatwa, fòma valab).
Etap 2: Lòd
pri inite, Kantite, Pousantaj taks, Derive: Sou-total, Taks, Total.
Etap 3: Kont & Feedback
Ou gen yon kont? (Wi/Non) Si Wi → non itilizatè + modpas, tou de obligatwa. Si Non → imel yo deja kolekte nan etap 1.
Evalyasyon Satisfaksyon (1–5) Si ≥ 4 → mande "Kisa ou te renmen?" Si ≤ 2 → mande "Kisa nou ka amelyore?"
Etap 4: Revize
Sèlman parèt si total >= 100 Soumèt final la.
Sa a se pa ekstrèm. Men, li ase yo ekspoze diferans achitekti. Pati 1: Konpozan Kondwi (Fòm Hook Reyaksyon + Zod) Enstalasyon npm enstale react-hook-form zod @hookform/resolvers @tanstack/react-query
Zod Schema Ann kòmanse ak chema Zod la, paske se nòmalman kote fòm fòm lan vin etabli. Pou de premye etap yo - detay pèsonèl ak opinyon lòd - tout bagay se senp: fisèl obligatwa, nimewo ki gen minimòm, ak yon enum. Pati enteresan an kòmanse lè ou eseye eksprime règ kondisyonèl yo.
enpòte {z} soti nan "zod";
ekspòtasyon const formSchema = z.object({ firstName: z.string().min(1, "Oblije"), imèl: z.string().email ("Envalid imèl"), pri: z.number().min(0), kantite: z.number().min(1), taxRate: z.number(), hasAccount:(No"]Y.esum" z.string().opsyonèl(), modpas: z.string().opsyonèl(),satisfaksyon:z.number().min(1).max(5), positiveFeedback: z.string().optional(), improvementFeedback: z.string().optional(),}).superRefine((done, ctx) => {si (data, ctx) => {si (data, ctx) => {si (data, ctx) => {si (data, ctx) => {si (data, ctx). ctx.addIssue({ kòd: "custom", chemen: ["username"], mesaj: "Oblije" }); } if (!data.password || data.password.length < 6) { ctx.addIssue({ kòd: "custom", chemen: ["modpas"], mesaj: "Min 6 karaktè}"});
si (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ kòd: "custom", chemen: ["positiveFeedback"], mesaj: "Tanpri pataje sa ou renmen" }); }
si (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue ({ kòd: "custom", chemen:["improvementFeedback"], mesaj: "Tanpri, di nou kisa pou amelyore"}); }});
ekspòtasyon kalite FormData = z.infer
Remake non itilizatè ak modpas yo tape kòm opsyonèl () menm si yo kondisyonèl obligatwa paske chema nivo kalite Zod la dekri fòm objè a, pa règ ki gouvène lè jaden yo enpòtan. Kondisyon kondisyonèl la gen pou viv andedan superRefine, ki kouri apre yo fin valide fòm nan epi li gen aksè a objè a plen. Separasyon sa a se pa yon defo; se jis pou sa zouti a fèt: superRefine se kote lojik kwa-champ ale lè li pa ka eksprime nan estrikti nan chema tèt li. Sa ki remakab tou isit la se sa chema sa a pa eksprime. Li pa gen okenn konsèp nan paj, pa gen okenn konsèp nan ki jaden yo vizib nan ki pwen, ak pa gen okenn konsèp nan navigasyon. Tout sa pral viv yon lòt kote. Eleman Fòm
enpòte { useForm, useWatch } soti nan "react-hook-form";enpòte { zodResolver } soti nan "@hookform/resolvers/zod"; enpòte { useMutation } soti nan "@tanstack/react-query";enpòte { useState, useMemo } soti nan "react";enpòte { formSchema, ki soti nan "FormDataschema";
const STEPS = ["detay", "lòd", "kont", "revizyon"];
tape OrderPayload = FormData & { subtotal: nimewo; taks: nimewo; total: nimewo };
fonksyon ekspòtasyon RHFMultiStepForm () { const [etap, setStep] = useState (0);
konst mutation = useMutation({ mutationFn: async (chaj: OrderPayload) => { const res = tann chache ("/api/lòd", { metòd: "POST", headers: {"Content-Type": "application/json" }, kò: JSON.stringify (chaj), }); si (!res.ok) voye nouvo Erè ("Echwe pou soumèt"); retounen res.json(); }, });
const { register, control, handleSubmit, formState: { errors }, } = useForm
retounen (
);}Gade Pen SurveyJS-03-RHF [forked] pa sixthextinction. Gen anpil bagay k ap pase isit la, epi li vo ralanti pou remake kote bagay yo te fini.
Valè ki sòti yo - subtotal, taks, total - yo kalkile nan eleman an atravè useWatch ak useMemo paske yo depann de valè jaden ap viv epi pa gen okenn lòt kote natirèl pou yo. Règ vizibilite pou non itilizatè, modpas, pozitif Feedback, ak amelyorasyon Feedback ap viv nan JSX kòm kondisyonèl enline. Lojik pou sote etap la — paj revizyon an parèt sèlman lè total >= 100 — entegre nan varyab showSubmit la ak kondisyon rann nan etap 3. Navigasyon tèt li se jis yon kontwa useState ke nou ap ogmante manyèlman. React Query okipe retay, kachèt, ak envalidasyon. Fòm nan jis rele mutation.mutate ak done valide.
Okenn nan sa a pa mal, per se. Sa a se toujou React idyomatik, ak eleman nan se byen pèfòmans gras a ki jan RHF izole re-rann. Men, si ou ta remèt sa a bay yon moun ki pa t ekri li epi mande yo eksplike nan ki kondisyon paj revizyon an parèt, yo ta dwe trase atravè showSubmit, etap 3 kondisyon an rann, ak lojik bouton nav la - twa kote separe - pou rekonstwi yon règ ki ta ka endike nan yon sèl liy. Fòm nan travay, wi, men konpòtman an pa vrèman enspekte kòm yon sistèm. Li dwe egzekite mantalman. Sa ki pi enpòtan, chanje li mande pou patisipasyon jeni. Menm yon ti ajisteman, tankou ajiste lè etap revizyon an parèt, vle di modifye eleman an, mete ajou validasyon, louvri yon demann rale, tann revizyon, epi deplwaye ankò. Pati 2: Chema-kondwi (SurveyJS) Koulye a, kite a bati menm koule lè l sèvi avèk yon chema. Enstalasyon npm enstale sondaj-debaz sondaj-react-ui @tanstack/react-query
survey-coreMotè egzekisyon MIT ki gen lisans sou platfòm la ki pèmèt rann fòm SurveyJS la - pati nou pran swen isit la. Li pran yon chema JSON, bati yon modèl entèn soti nan li, ak okipe tout sa ki ta ka viv nan eleman React ou a: evalye ekspresyon vizibilite, kalkile valè ki sòti, jere eta paj, swiv validation, ak deside kisa "konplè" vle di bay ki paj yo te aktyèlman montre.
survey-react-ui Kouch UI / rann ki konekte modèl sa a ak React. Li se esansyèlman yon eleman
Ansanm, yo ba ou yon totalman fonksyonèl, milti-paj fòm ègzekutabl san yo pa ekri yon sèl liy nan koule kontwòl. Fòma chema nan tèt li se, jan yo di anvan, jis yon JSON - pa gen okenn DSL oswa anyen propriétaires. Ou ka aliye li, enpòte li soti nan yon fichye, chache li nan yon API, oswa estoke li nan yon kolòn baz done epi idrat li nan kouri. Fòm nan menm, kòm done Men menm fòm lan, fwa sa a eksprime kòm yon objè JSON. Chema a defini tout bagay: estrikti, validation, règ vizibilite, kalkil ki sòti, navigasyon paj - epi li remèt li bay yon Modèl ki evalye li nan kouri. Men sa ki sanble an plen:
export const surveySchema = { title: "Order Flow", showProgressBar: "top", paj: [ { non: "detay", eleman: [ { type: "text", name: "firstName", isRequired: true }, { type: "text", name: "email", inputType: "email", isRequired: true, validators: [} type: "Imel"], text non: "lòd", eleman: [ { kalite: "tèks", non: "pri", inputType: "nimewo", defaultValue: 0}, { kalite: "tèks", non: "kantite", inputType: "nimewo", defaultValue: 1}, { kalite: "dropdown",non: "taxRate", defaultValue: 0.1, chwa: [ {valè: 0.05, tèks: "5%" }, { valè: 0.1, tèks: "10%" }, { valè: 0.15, tèks: "15%" } ] }, { kalite: "ekspresyon", non: "sous-total",} ekspresyon: "kantite" "," ekspresyon: ": ": "" "taks", ekspresyon: "{subtotal} {taxRate}" }, { kalite: "ekspresyon", non: "total", ekspresyon: "{subtotal} + {taks}" } ] }, { non: "kont", eleman: [ { type: "radyogroup", non: "hasAccount", chwa: ["Wi", "Non"] }, non vizib, {:::" nou non" "{hasAccount} = 'Wi'", isRequired: vre }, {type: "tèks", non: "modpas", inputType: "modpas", visibleIf: "{hasAccount} = 'Wi'", isRequired: vre, validateurs: [{ type: "text", minLength: 6, text: "Min 6 characters}," {}:] "factions" rateMin: 1, rateMax: 5 }, { type: "comment", non: "positiveFeedback", visibleIf: "{satisfaksyon} >= 4" }, { type: "comment", non: "improvementFeedback", visibleIf: "{satisfaction} <= 2" } ] }, {}: >: "review eleman", {}: >: "review" [] } ]};
Konpare sa a ak vèsyon an RHF pou yon moman.
Blòk superRefine ki kondisyonèl mande non itilizatè ak modpas la disparèt. visibleIf: "{hasAccount} = 'Wi'" konbine avèk isRequired: vre okipe tou de enkyetid ansanm, sou teren an li menm, kote ou ta espere jwenn yo. Chèn useWatch + useMemo ki kalkile subtotal, taks, ak total ranplase pa twa jaden ekspresyon ki fè referans youn ak lòt pa non. Kondisyon paj revizyon an, ki nan vèsyon an RHF te rekonstwi sèlman pa trase atravè showSubmit, etap 3 rann branch lan. Epi finalman, lojik bouton nav la se yon sèl pwopriyete visibleIf sou objè paj la.
Menm lojik la genyen. Se jis ke chema a ba li yon kote pou viv kote li vizib nan izolasyon, olye ke gaye atravè eleman an. Epitou, sonje ke chema a sèvi ak kalite: 'ekspresyon' pou subtotal, taks, ak total. Ekspresyon se lekti sèlman epi li itilize sitou pou montre valè kalkile yo. SurveyJS sipòte tou kalite: 'html' pou kontni estatik, men pou valè kalkile, ekspresyon se bon chwa. Koulye a, pou bò React. Rann ak soumèt Trè senp. Wire onComplete nan API ou a menm jan an - atravè useMutation oswa plenn chache:
enpòte { useState, useEffect, useRef } soti nan "react";enpòte { useMutation } soti nan "@tanstack/react-query";enpòte { Model } soti nan "survey-core";enpòte { Survey } soti nan "survey-react-ui";enpòte "survey-core/survey-core.css";
fonksyon ekspòtasyon SurveyForm () { const [modèl] = useState (() => nouvo Modèl (surveySchema));
konst mutation = useMutation({ mutationFn: async (done) => { const res = tann chache ("/api/lòd", { metòd: "POST", headers: {"Content-Type": "application/json" }, kò: JSON.stringify (done), }); si (!res.ok) voye nouvo Erè ("Echwe pou soumèt"); retounen res.json(); }, });
const mutationRef = useRef(mitasyon); mutationRef.current = mitasyon; useEffect(() => { const handler = (sender) => mutationRef.current.mutate (sender.data); model.onComplete.add (handler); return () => model.onComplete.remove (handler); }, [model]); // ref evite re-anrejistre moun kap okipe chak rann (chanjman idantite objè mitasyon)
retounen (
<>
Gade Pen SurveyJS-03-SurveyJS [forked] pa sixthextinction.
onComplete dife lè itilizatè a rive nan fen dènye paj vizib la. Se konsa, si total pa janm kwaze 100 epi yo sote paj revizyon an, li toujou dife kòrèkteman paske SurveyJS evalye vizibilite anvan li deside kisa "dènye paj" vle di. Lè sa a, sender.data gen tout repons ansanm ak valè yo kalkile (sous-total, taks, total) kòm jaden premye klas, kidonk chaj API a idantik ak sa ki vèsyon RHF reyini manyèlman nan onSubmit. Lamodèl mutationRef se menm bagay ou ta jwenn nenpòt kote ou bezwen yon moun kap okipe evènman ki estab sou yon valè ki chanje sou chak rann - pa gen anyen SurveyJS-espesifik sou li.
Eleman React la pa gen okenn lojik biznis ankò. Pa gen okenn useWatch, pa gen okenn JSX kondisyonèl, pa gen okenn kontwa etap, pa gen okenn chèn useMemo, pa gen okenn superRefine. React ap fè sa li vrèman bon nan: rann yon eleman ak fil elektrik li nan yon apèl API. Ki sa ki te deplase soti nan reyaji?
Enkyetid Pile RHF SondajJS Vizibilite Branch JSX vizibSi Valè sòti itilize Gade / itilizeMemo ekspresyon Règ Cross-field superRafine Kondisyon chema yo Navigasyon eta etap Paj vizibSi Kote règ Distribiye atravè dosye Santralize nan chema a
Ki sa ki rete nan React se layout, manier, fil elektrik soumèt, ak entegrasyon app, ki vle di, bagay sa yo React aktyèlman fèt pou yo. Tout lòt bagay te deplase nan chema a, epi paske chema a se jis yon objè JSON, li ka estoke nan yon baz done, vèsyon poukont kòd aplikasyon w lan, oswa modifye atravè zouti entèn san yo pa bezwen yon deplwaye. Yon manadjè pwodwi ki bezwen chanje papòt ki deklanche paj revizyon an ka fè sa san yo pa manyen eleman an. Sa a se yon diferans operasyon enpòtan pou ekip kote konpòtman fòm evolye souvan epi li pa toujou kondwi pa enjenyè. Ki lè pou itilize chak apwòch? Men yon bon règ ki travay pou mwen: imajine efase fòm nan nèt. Kisa ou ta pèdi?
Si se ekran, ou vle fòm konpozan kondwi. Si se lojik biznis, tankou papòt, règ branche, ak kondisyon kondisyonèl ki kode desizyon reyèl, ou vle yon motè chema.
Menm jan an tou, si chanjman k ap vini yo se sitou sou etikèt, jaden, ak layout, RHF ap sèvi ou byen. Si yo konsène kondisyon, rezilta, ak règ ke ops ou oswa ekip legal ou a ta ka bezwen ajiste nan yon madi apremidi san yo pa ranpli yon tikè, modèl la chema ak SurveyJS se anfòm ki pi onèt. De apwòch sa yo pa vrèman nan konpetisyon youn ak lòt. Yo adrese diferan klas pwoblèm, ak erè ki merite pou evite se dezakò nan abstraksyon an ak pwa lojik la - trete yon sistèm règ tankou yon eleman paske se zouti ki abitye, oswa rive jwenn yon motè politik paske yon fòm te grandi nan twa etap ak akeri yon jaden kondisyonèl. Fòm nou bati isit la chita tou pre fwontyè a fè espre, konplèks ase yo ekspoze diferans lan men pa tèlman ekstrèm ke konparezon an santi yo truke. Pifò fòm reyèl ki te vin lou nan kodbaz ou a pwobableman chita tou pre menm fwontyè sa a, ak kesyon an anjeneral jis si nenpòt moun te nonmen sa yo aktyèlman yo ye. Sèvi ak React Hook Form + Zod lè:
Fòm yo oryante sou CRUD; Lojik se fon ak UI-kondwi; Enjenyè posede tout konpòtman; Backend rete sous verite a.
Sèvi ak SurveyJS lè:
Fòm kode desizyon biznis yo; Règ yo evolye poukont UI; Lojik dwe vizib, odit, oswa vèsyon; Ki pa enjenyè enfliyanse konpòtman; Fòm nan menm dwe kouri atravè plizyè entèfas.