Þessi grein er styrkt af SurveyJS Það er andlegt líkan sem flestir React verktaki deila án þess að ræða það upphátt. Að form eiga alltaf að vera hluti. Þetta þýðir stafla eins og:
React Hook Eyðublað fyrir staðbundið ríki (lágmarks endurútgáfur, vinnuvistfræðileg sviðsskráning, nauðsynleg samskipti). Zod fyrir staðfestingu (réttmæti inntaks, staðfesting á mörkum, tegundarörugg þáttun). React Query fyrir bakenda: uppgjöf, endurtilraunir, skyndiminni, samstilling netþjóns og svo framvegis.
Og fyrir langflest eyðublöð - innskráningarskjár, stillingasíður þínar, CRUD gerðir - þetta virkar mjög vel. Hvert stykki vinnur sitt, þeir semja hreint og þú getur farið yfir í þá hluta forritsins sem í raun aðgreina vöruna þína. En öðru hvoru byrjar eyðublað að safna hlutum eins og sýnileikareglum sem eru háðar fyrri svörum, eða afleidd gildi sem falla í gegnum þrjú svið. Kannski jafnvel heilar síður sem ætti að sleppa eða sýna miðað við heildarfjölda. Þú höndlar fyrsta skilyrt með useWatch og innbyggðri grein, sem er í lagi. Síðan annað. Þá ertu að ná í superRefine til að umrita þversviðsreglur sem Zod stefið þitt getur ekki tjáð á venjulegan hátt. Síðan byrjar skrefaleiðsögn að leka viðskiptarökfræði. Á einhverjum tímapunkti horfirðu á það sem þú hefur smíðað og áttar þig á því að formið er í raun ekki notendaviðmót lengur. Þetta er meira ákvörðunarferli og íhlutatréð er bara þar sem þú geymdir það. Þetta er þar sem ég held að andlega líkanið fyrir form í React brotni niður og það er í raun engum að kenna. RHF + Zod staflan er frábær í því sem hann var hannaður fyrir. Málið er að við höfum tilhneigingu til að halda áfram að nota það framhjá þeim tímapunkti þar sem útdráttur þess passar við vandamálið vegna þess að valkosturinn krefst annars konar hugsunar um form algjörlega. Þessi grein er um þann valkost. Til að sýna þetta munum við smíða nákvæmlega sama fjölþrepa eyðublaðið tvisvar:
Með React Hook Form + Zod tengt við React Query til framlagningar, Með SurveyJS, sem meðhöndlar form sem gögn - einfalt JSON skema - frekar en íhlutatré.
Sömu kröfur, sama skilyrta rökfræði, sama API kall í lokin. Síðan munum við kortleggja nákvæmlega hvað hreyfðist og hvað varð eftir, og útlista hagnýta leið til að ákveða hvaða líkan þú ættir að nota og hvenær. Eyðublaðið sem við erum að byggja:
Þetta eyðublað mun nota 4 þrepa flæði: Skref 1: Upplýsingar
Fornafn (áskilið), Tölvupóstur (áskilið, gilt snið).
Skref 2: Panta
Einingaverð, Magn, Skatthlutfall, Afleitt: Samtala, Skattur, Samtals.
Skref 3: Reikningur og endurgjöf
Ertu með reikning? (Já/Nei) Ef Já → notandanafn + lykilorð, bæði krafist. Ef nei → tölvupóstur þegar safnað í skrefi 1.
Ánægjueinkunn (1–5) Ef ≥ 4 → spyrðu „Hvað líkaði þér?“ Ef ≤ 2 → spyrðu "Hvað getum við bætt?"
Skref 4: Skoðaðu
Birtist aðeins ef samtals >= 100 Lokaskil.
Þetta er ekki öfgafullt. En það er nóg til að afhjúpa byggingarfræðilegan mun. Hluti 1: Íhlutadrifinn (React Hook Form + Zod) Uppsetning npm setja upp react-hook-form zod @hookform/resolvers @tanstack/react-query
Zod Skema Byrjum á Zod stefinu, því það er venjulega þar sem lögun eyðublaðsins festist. Fyrir fyrstu tvö skrefin - persónulegar upplýsingar og pöntunarinntak - er allt einfalt: nauðsynlegir strengir, tölur með lágmarki og upptalning. Hinn áhugaverði hluti byrjar þegar þú reynir að tjá skilyrtu reglurnar.
flytja inn { z } úr "zod";
export const formSchema = z.object({ fornafn: z.string().min(1, "Áskilið"), netfang: z.string().email("Ógilt netfang"), verð: z.number().min(0), magn: z.number().min(1), skatthlutfall: z.number(), hasAccount: z.enum(No["Já),op notandi "No["Já"). lykilorð: z.string().valfrjálst(), fullnæging: z.number().min(1).max(5), jákvæð viðbrögð: z.string().valfrjálst(), endurbætur: z.string().valfrjálst(),}).superRefine((gögn, ctx) => { if (data.hasAccounter ===) "Já" ctx.addIssue({kóði: "sérsniðin", slóð: ["notandanafn"], skilaboð: "Áskilið" } } if (!data.password || data.addIssue < 6) { ctx.addIssue({kóði: "sérsniðið", slóð: ["lykilorð"], skilaboð: "Lágmark 6 stafir"});
if (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ code: "custom", path: ["positiveFeedback"], skilaboð: "Vinsamlegast deildu því sem þér líkaði" }); }
if (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue({ kóða: "sérsniðin", slóð:["improvementFeedback"], skilaboð: "Vinsamlegast segðu okkur hvað við eigum að bæta" }); }});
útflutningsgerð FormData = z.infer
Taktu eftir að notendanafn og lykilorð eru slegin inn sem valfrjálst() jafnvel þó að þau séu skilyrðisbundin vegna þess að tegundarstigsskema Zod lýsir lögun hlutarins, ekki reglurnar um hvenær reitir skipta máli. Skilyrta krafan verður að búa inni í superRefine, sem keyrir eftir að lögunin hefur verið staðfest og hefur aðgang að öllu hlutnum. Sá aðskilnaður er ekki galli; það er bara það sem tólið er hannað fyrir: superRefine er þar sem þversviðsrökfræði fer þegar það er ekki hægt að tjá hana í skemaskipulaginu sjálfu. Það sem er líka athyglisvert hér er það sem þetta skema tjáir ekki. Það hefur ekki hugmynd um síður, ekkert hugmynd um hvaða svið eru sýnileg á hvaða tímapunkti og ekkert hugtak um flakk. Allt þetta mun lifa annars staðar. Form hluti
flytja inn { useForm, useWatch } frá "react-hook-form"; flytja inn { zodResolver } frá "@hookform/resolvers/zod"; flytja inn { useMutation } frá "@tanstack/react-query"; flytja inn { useState, useMemo } frá "react"; import { formSchema} frá "FormDataSchema};
const STEPS = ["upplýsingar", "pöntun", "reikningur", "endurskoðun"];
type OrderPayload = FormData & { subtotal: number; skattur: tala; samtals: tala };
útflutningsfall RHFMultiStepForm() { const [skref, setStep] = useState(0);
const stökkbreyting = useStökkbreyting({ mutationFn: ósamstilltur (payload: OrderPayload) => { const res = await fetch("/api/orders", { aðferð: "POST", hausar: { "Content-Type": "application/json" }, meginmál: JSON.stringify(hleðsla), }); if (!res.ok) throw new Error("Mistókst að senda inn"); skila res.json(); }, });
const { register, control, handleSubmit, formState: { errors }, } = useForm
skila (
);}Sjá Pen SurveyJS-03-RHF [gaflað] með sextextinction. Hér er ansi margt að gerast og það er þess virði að hægja á sér til að taka eftir því hvar hlutirnir enduðu.
Afleiddu gildin - meðaltala, skattur, heildarfjöldi - eru reiknuð út í íhlutnum í gegnum useWatch og useMemo vegna þess að þau eru háð gildum á lifandi sviði og það er enginn annar náttúrulegur staður fyrir þau. Sýnileikareglur fyrir notandanafn, lykilorð, jákvæða endurgjöf og endurbætur eru birtar í JSX sem innbyggð skilyrði. Skref-sleppingarrökfræðin - endurskoðunarsíðan sem birtist aðeins þegar samtals >= 100 - er felld inn í showSubmit breytuna og birtingarskilyrðið í skrefi 3. Leiðsögnin sjálf er bara useState teljari sem við erum að hækka handvirkt. React Query sér um endurtilraunir, skyndiminni og ógildingu. Eyðublaðið kallar bara mutation.mutate með staðfestum gögnum.
Ekkert af þessu er rangt, í sjálfu sér. Þetta er enn ídiomatic React, og íhluturinn er nokkuð árangursríkur þökk sé því hvernig RHF einangrar endurútgáfur. En ef þú myndir afhenda þetta einhverjum sem hafði ekki skrifað það og biðja hann um að útskýra við hvaða aðstæður endurskoðunarsíðan birtist, þá þyrftu þeir að rekja í gegnum showSubmit, skref 3 birtingarskilyrði og nav hnappinn - þrjá aðskilda staði - til að endurbyggja reglu sem hefði getað verið sett fram í einni línu. Eyðublaðið virkar, já, en hegðunin er í raun ekki skoðanleg sem kerfi. Það þarf að framkvæma andlega. Meira um vert, að breyta því krefst verkfræðiþátttöku. Jafnvel smá lagfæring, eins og að stilla þegar endurskoðunarskrefið birtist, þýðir að breyta íhlutnum, uppfæra staðfestingu, opna útdráttarbeiðni, bíða eftir yfirferð og setja upp aftur. Part 2: Schema-Driven (SurveyJS) Nú skulum við byggja sama flæði með skema. Uppsetning npm setja upp survey-core survey-react-ui @tanstack/react-query
survey-coreHin MIT-leyfislausa vettvangsóháða keyrsluvél sem knýr myndbirtingu SurveyJS - hlutinn sem okkur þykir vænt um hér. Það tekur JSON skema, byggir innra líkan úr því og sér um allt sem annars myndi búa í React íhlutnum þínum: að meta sýnileikatjáningu, reikna út afleidd gildi, stjórna síðuástandi, rekja löggildingu og ákveða hvað „lokið“ þýðir miðað við hvaða síður voru í raun sýndar.
survey-react-ui Notendaviðmótið / flutningslagið sem tengir það líkan við React. Það er í rauninni
Saman gefa þeir þér fullkomlega virkan, margra blaðsíðna keyrslutíma án þess að skrifa eina línu af stjórnflæði. Skemasniðið sjálft er, eins og áður sagði, bara JSON - ekkert DSL eða neitt séreign. Þú getur sett það inn, flutt það inn úr skrá, sótt það úr API eða geymt það í gagnagrunnsdálki og vökvað það á keyrslutíma. Sama form, sem gögn Hér er sama form, að þessu sinni gefið upp sem JSON hlutur. Skemanið skilgreinir allt: uppbyggingu, löggildingu, sýnileikareglur, afleidda útreikninga, síðuleiðsögn - og afhendir það líkani sem metur það á keyrslutíma. Svona lítur það út í heild sinni:
export const surveySchema = { title: "Order Flow", showProgressBar: "top", síður: [ { name: "details", elements: [ { type: "text", name: "firstName", isRequired: true }, { type: "text", name: "email", inputType: "email", isRequired: true, "validemail": [{ tegund: " }, { nafn: "pöntun", þættir: [ { type: "texti", nafn: "price", inputType: "number", defaultValue: 0 }, { type: "text", nafn: "quantity", inputType: "number", defaultValue: 1 }, { type: "dropdown",nafn: "taxRate", defaultValue: 0.1, val: [ { value: 0.05, text: "5%" }, { value: 0.1, text: "10%" }, { value: 0.15, text: "15%" } ] }, { type: "expression", name: "quantity{subtotal}"} expression: " "tjáning", nafn: "skattur", tjáning: "{subtotal} {taxRate}" }, { type: "expression", nafn: "total", tjáning: "{subtotal} + {tax}" } ] }, { nafn: "reikningur", þættir: [ { type: "radiogroup", nafn: "hasAccount", valkostir: ["]texti "us",: "No type" visibleIf: "{hasAccount} = 'Já'", erRequired: true }, { type: "text", name: "password", inputType: "password", visibleIf: "{hasAccount} = 'Já'", erRequired: true, validators: [{ type: "text", minLength: "6, characters: "Min:r name", texts: "Min:r" "ánægja", hlutfallMín: 1, hlutfallHámark: 5 }, { type: "comment", name: "positiveFeedback", visibleIf: "{satisfaction} >= 4" }, { type: "comment", name: "improvementFeedback", visibleIf: "{satisfaction} <= 2" } "f re:" } sýnilegt >= 100", þættir: [] } ]};
Berðu þetta saman við RHF útgáfuna í smá stund.
SuperRefine blokkin sem skilyrt þurfti notandanafn og lykilorð er horfin. visibleIf: "{hasAccount} = 'Já'" ásamt isRequired: true sér um báðar áhyggjurnar saman, á vellinum sjálfum, þar sem þú gætir búist við að finna þau. UseWatch + useMemo keðjunni sem reiknaði út millitölu, skatta og heildartölu er skipt út fyrir þrjá tjáningarreita sem vísa hver til annars með nafni. Ástand endurskoðunarsíðunnar, sem í RHF útgáfunni var aðeins hægt að endurbyggja með því að rekja í gegnum showSubmit, skref 3 birta grein. Og að lokum, rökfræði nav hnappsins er ein visibleIf eign á síðuhlutnum.
Sama rökfræði er þarna. Það er bara að stefið gefur því stað til að búa þar sem það er sýnilegt í einangrun, frekar en að dreifast yfir íhlutinn. Athugaðu líka að stefið notar gerð: 'tjáning' fyrir undirtölu, skatta og heildar. Tjáning er eingöngu skrifleg og notuð aðallega til að sýna reiknuð gildi. SurveyJS styður einnig gerð: 'html' fyrir kyrrstætt efni, en fyrir útreiknuð gildi er tjáning rétti kosturinn. Nú fyrir React hliðina. Útgáfa og uppgjöf Mjög einfalt. Kveiktu á Complete við API á sama hátt - með useMutation eða venjulegri niðurhali:
flytja inn { useState, useEffect, useRef } frá "react"; flytja inn { useMutation } frá "@tanstack/react-query"; flytja inn { Model } frá "survey-core"; flytja inn { Survey } frá "survey-react-ui"; flytja inn "survey-core/survey"-;
útflutningsfall SurveyForm() { const [líkan] = useState(() => nýtt líkan(könnunarskema));
const stökkbreyting = useStökkbreyting({ mutationFn: ósamstilltur (gögn) => { const res = await fetch("/api/orders", { aðferð: "POST", hausar: { "Content-Type": "application/json" }, meginmál: JSON.stringify(gögn), }); if (!res.ok) throw new Error("Mistókst að senda inn"); skila res.json(); }, });
const mutationRef = useRef(stökkbreyting); mutationRef.current = stökkbreyting; useEffect(() => { const handler = (sender) => mutationRef.current.mutate(sender.data); model.onComplete.add(handler); return () => model.onComplete.remove(handler); }, [líkan]); // ref forðast endurskráningu meðhöndlunar í hverri myndgerð (stökkbreytingarhlutur breytist)
skila (
<>
Sjá Pen SurveyJS-03-SurveyJS [gaflað] með sixthextinction.
onComplete ræsir þegar notandi nær lok síðustu sýnilegu síðunnar. Þannig að ef heildarfjöldi fer aldrei yfir 100 og skoðunarsíðunni er sleppt, þá ræsir hún samt rétt vegna þess að SurveyJS metur sýnileika áður en ákveðið er hvað „síðasta síða“ þýðir. Síðan inniheldur sender.data öll svör ásamt útreiknuðum gildum (subtotal, tax, total) sem fyrsta flokks reiti, þannig að API gagnálag er eins og RHF útgáfan setti saman handvirkt í onSubmit. ThemutationRef mynstur er það sama og þú myndir ná til hvar sem þú þarft stöðugan atburðastjórnun yfir gildi sem breytist við hverja flutning – ekkert SurveyJS-sérstakt við það.
React íhluturinn inniheldur alls ekki lengur viðskiptarökfræði. Það er engin useWatch, engin skilyrt JSX, enginn skrefateljari, engin useMemo keðja, engin superRefine. React er að gera það sem það er í raun gott í: að skila íhlut og tengja hann við API símtal. Hvað færðist út úr React?
Áhyggjur RHF stafla SurveyJS Skyggni JSX útibú sýnilegt Ef Afleidd gildi useWatch / useMemo tjáningu Þvervallarreglur superRefine Skipulagsskilyrði Leiðsögn skrefa ástand Síða sýnilegEf Regla staðsetningu Dreift yfir skrár Miðstýrt í skema
Það sem helst í React er skipulag, stíll, uppgjöf raflögn og samþætting forrita, sem er að segja það sem React er í raun hannað fyrir. Allt annað flutt inn í skemað og vegna þess að stefið er bara JSON hlutur, er hægt að geyma það í gagnagrunni, útgáfa óháð forritskóðanum þínum, eða breyta með innri verkfærum án þess að þurfa uppsetningu. Vörustjóri sem þarf að breyta þröskuldinum sem kallar á skoðunarsíðuna getur gert það án þess að snerta íhlutinn. Það er þýðingarmikill rekstrarmunur fyrir teymi þar sem formhegðun þróast oft og er ekki alltaf knúin áfram af verkfræðingum. Hvenær á að nota hverja aðferð? Hér er góð þumalputtaregla sem virkar fyrir mig: ímyndaðu þér að eyða eyðublaðinu alveg. Hverju myndirðu tapa?
Ef það eru skjáir, viltu íhlutadrifin eyðublöð. Ef það er viðskiptarökfræði, eins og þröskuldar, greiningarreglur og skilyrtar kröfur sem kóða raunverulegar ákvarðanir, viltu skemavél.
Á sama hátt, ef breytingarnar sem verða á vegi þínum snúast aðallega um merki, reiti og útlit, mun RHF þjóna þér vel. Ef þær snúast um skilyrði, niðurstöður og reglur sem starfandi eða lögfræðiteymi gæti þurft að laga á þriðjudagseftirmiðdegi án þess að leggja inn miða, þá er skemalíkanið með SurveyJS heiðarlegra. Þessar tvær aðferðir eru í raun ekki í samkeppni hver við aðra. Þeir taka á mismunandi flokkum vandamála og mistökin sem vert er að forðast er að misræma abstraktið við vægi rökfræðinnar - að meðhöndla reglukerfi eins og hluti vegna þess að það er kunnuglega tólið, eða ná til stefnumótunar vegna þess að form stækkaði í þrjú þrep og fékk skilyrt svið. Formið sem við smíðuðum hér situr vísvitandi nálægt landamærunum, nógu flókið til að afhjúpa muninn en ekki svo öfgafullt að samanburðurinn finnist vera rangur. Flest raunveruleg form sem hafa orðið ómeðhöndluð í kóðagrunninum þínum sitja líklega nálægt sömu mörkum og spurningin er yfirleitt bara hvort einhver hafi nefnt hvað þau eru í raun og veru. Notaðu React Hook Form + Zod þegar:
Eyðublöð eru CRUD-stilla; Rökfræði er grunn og UI-drifin; Verkfræðingar eiga alla hegðun; Bakenda er áfram uppspretta sannleikans.
Notaðu SurveyJS þegar:
Eyðublöð umrita viðskiptaákvarðanir; Reglur þróast óháð HÍ; Rökfræði verður að vera sýnileg, endurskoðanleg eða útfærð; Þeir sem ekki eru verkfræðingar hafa áhrif á hegðun; Sama form verður að keyra yfir marga framenda.