ഈ ലേഖനം സർവേജെഎസ് സ്പോൺസർ ചെയ്തതാണ് മിക്ക റിയാക്റ്റ് ഡെവലപ്പർമാരും ഒരിക്കലും ഉച്ചത്തിൽ ചർച്ച ചെയ്യാതെ പങ്കിടുന്ന ഒരു മാനസിക മാതൃകയുണ്ട്. ആ രൂപങ്ങൾ എല്ലായ്‌പ്പോഴും ഘടകങ്ങളായിരിക്കണം. ഇതുപോലുള്ള ഒരു ശേഖരം എന്നാണ് ഇതിനർത്ഥം:

പ്രാദേശിക സംസ്ഥാനത്തിനായുള്ള റിയാക്റ്റ് ഹുക്ക് ഫോം (കുറഞ്ഞ റീ-റെൻഡറുകൾ, എർഗണോമിക് ഫീൽഡ് രജിസ്ട്രേഷൻ, നിർബന്ധിത ഇടപെടൽ). മൂല്യനിർണ്ണയത്തിനുള്ള സോഡ് (ഇൻപുട്ട് കൃത്യത, അതിർത്തി മൂല്യനിർണ്ണയം, ടൈപ്പ്-സേഫ് പാഴ്‌സിംഗ്). ബാക്കെൻഡിനായുള്ള പ്രതികരണ ചോദ്യം: സമർപ്പിക്കൽ, വീണ്ടും ശ്രമിക്കൽ, കാഷെ ചെയ്യൽ, സെർവർ സമന്വയം തുടങ്ങിയവ.

കൂടാതെ ബഹുഭൂരിപക്ഷം ഫോമുകൾക്കും - നിങ്ങളുടെ ലോഗിൻ സ്ക്രീനുകൾ, നിങ്ങളുടെ ക്രമീകരണ പേജുകൾ, നിങ്ങളുടെ CRUD മോഡലുകൾ - ഇത് വളരെ നന്നായി പ്രവർത്തിക്കുന്നു. ഓരോ ഭാഗവും അതിൻ്റെ ജോലി ചെയ്യുന്നു, അവ വൃത്തിയായി രചിക്കുന്നു, നിങ്ങളുടെ ഉൽപ്പന്നത്തെ യഥാർത്ഥത്തിൽ വ്യത്യസ്തമാക്കുന്ന നിങ്ങളുടെ ആപ്ലിക്കേഷൻ്റെ ഭാഗങ്ങളിലേക്ക് നിങ്ങൾക്ക് പോകാം. എന്നാൽ ഇടയ്‌ക്കിടെ, ഒരു ഫോം മുമ്പത്തെ ഉത്തരങ്ങളെ ആശ്രയിച്ചിരിക്കുന്ന ദൃശ്യപരത നിയമങ്ങൾ അല്ലെങ്കിൽ മൂന്ന് ഫീൽഡുകളിലൂടെ കാസ്കേഡ് ചെയ്യുന്ന മൂല്യങ്ങൾ പോലുള്ള കാര്യങ്ങൾ ശേഖരിക്കാൻ തുടങ്ങുന്നു. ഒരുപക്ഷേ മുഴുവൻ പേജുകളും ഒഴിവാക്കുകയോ അല്ലെങ്കിൽ പ്രവർത്തിക്കുന്ന മൊത്തത്തെ അടിസ്ഥാനമാക്കി കാണിക്കുകയോ ചെയ്യാം. ഒരു യൂസ്‌വാച്ചും ഇൻലൈൻ ബ്രാഞ്ചും ഉപയോഗിച്ച് നിങ്ങൾ ആദ്യ സോപാധികം കൈകാര്യം ചെയ്യുന്നു, അത് നല്ലതാണ്. പിന്നെ മറ്റൊന്ന്. നിങ്ങളുടെ Zod സ്കീമയ്ക്ക് സാധാരണ രീതിയിൽ പ്രകടിപ്പിക്കാൻ കഴിയാത്ത ക്രോസ്-ഫീൽഡ് നിയമങ്ങൾ എൻകോഡ് ചെയ്യാൻ നിങ്ങൾ സൂപ്പർ റിഫൈനിലേക്ക് എത്തുകയാണ്. തുടർന്ന്, സ്റ്റെപ്പ് നാവിഗേഷൻ ബിസിനസ്സ് ലോജിക് ചോർത്താൻ തുടങ്ങുന്നു. ചില ഘട്ടങ്ങളിൽ, നിങ്ങൾ എന്താണ് നിർമ്മിച്ചതെന്ന് നോക്കുകയും ഫോം യഥാർത്ഥത്തിൽ UI അല്ലെന്ന് മനസ്സിലാക്കുകയും ചെയ്യുന്നു. ഇത് കൂടുതൽ തീരുമാന പ്രക്രിയയാണ്, നിങ്ങൾ അത് സംഭരിക്കാൻ ഇടയായത് ഘടക ട്രീയാണ്. ഇവിടെയാണ് റിയാക്ടിലെ ഫോമുകളുടെ മാനസിക മാതൃക തകരുന്നത് എന്ന് ഞാൻ കരുതുന്നു, ഇത് ശരിക്കും ആരുടേയും തെറ്റല്ല. RHF + Zod സ്റ്റാക്ക് രൂപകൽപ്പന ചെയ്തതിൽ മികച്ചതാണ്. പ്രശ്‌നമായത്, അതിൻ്റെ അമൂർത്തങ്ങൾ പ്രശ്‌നവുമായി പൊരുത്തപ്പെടുന്ന ഘട്ടം മറികടന്ന് ഞങ്ങൾ അത് ഉപയോഗിക്കുന്നത് തുടരുന്നു എന്നതാണ്, കാരണം ബദലിന് ഫോമുകളെക്കുറിച്ചുള്ള വ്യത്യസ്തമായ ചിന്താഗതി ആവശ്യമാണ്. ഈ ലേഖനം ആ ബദലിനെക്കുറിച്ചാണ്. ഇത് കാണിക്കാൻ, ഞങ്ങൾ ഒരേ മൾട്ടി-സ്റ്റെപ്പ് ഫോം രണ്ടുതവണ നിർമ്മിക്കും:

റിയാക്റ്റ് ഹുക്ക് ഫോം + സോഡ് ഉപയോഗിച്ച്, സമർപ്പണത്തിനുള്ള അന്വേഷണത്തോട് പ്രതികരിക്കാൻ, ഒരു ഘടക ട്രീ എന്നതിലുപരി ഒരു ലളിതമായ JSON സ്കീമ - ഒരു ഫോം ഡാറ്റയായി പരിഗണിക്കുന്ന SurveyJS ഉപയോഗിച്ച്.

ഒരേ ആവശ്യകതകൾ, അതേ സോപാധിക യുക്തി, അവസാനം ഒരേ API കോൾ. തുടർന്ന്, എന്താണ് നീങ്ങിയതെന്നും എന്താണ് നിലനിൽക്കുന്നതെന്നും ഞങ്ങൾ കൃത്യമായി മാപ്പ് ചെയ്യുകയും ഏത് മോഡൽ എപ്പോൾ ഉപയോഗിക്കണമെന്നും തീരുമാനിക്കാനുള്ള പ്രായോഗിക മാർഗം തയ്യാറാക്കുകയും ചെയ്യും. ഞങ്ങൾ നിർമ്മിക്കുന്ന ഫോം:

ഈ ഫോം 4-ഘട്ട ഫ്ലോ ഉപയോഗിക്കും: ഘട്ടം 1: വിശദാംശങ്ങൾ

ആദ്യ നാമം (ആവശ്യമാണ്), ഇമെയിൽ (ആവശ്യമാണ്, സാധുവായ ഫോർമാറ്റ്).

ഘട്ടം 2: ഓർഡർ ചെയ്യുക

യൂണിറ്റ് വില, അളവ്, നികുതി നിരക്ക്, ഉരുത്തിരിഞ്ഞത്: ഉപമൊത്തം, നികുതി, ആകെ.

ഘട്ടം 3: അക്കൗണ്ടും ഫീഡ്‌ബാക്കും

നിങ്ങൾക്ക് ഒരു അക്കൗണ്ട് ഉണ്ടോ? (അതെ/ഇല്ല) അതെ എങ്കിൽ → ഉപയോക്തൃനാമം + പാസ്‌വേഡ്, രണ്ടും ആവശ്യമാണ്. ഇല്ലെങ്കിൽ → ഇമെയിൽ ഇതിനകം ഘട്ടം 1-ൽ ശേഖരിച്ചിട്ടുണ്ട്.

സംതൃപ്തി റേറ്റിംഗ് (1–5) ≥ 4 → ചോദിച്ചാൽ "നിങ്ങൾക്ക് എന്താണ് ഇഷ്ടപ്പെട്ടത്?" ≤ 2 → ചോദിക്കുകയാണെങ്കിൽ, "നമുക്ക് എന്ത് മെച്ചപ്പെടുത്താൻ കഴിയും?"

ഘട്ടം 4: അവലോകനം

ആകെ >= 100 ആണെങ്കിൽ മാത്രം ദൃശ്യമാകും അന്തിമ സമർപ്പണം.

ഇത് അതിരുകടന്നതല്ല. എന്നാൽ വാസ്തുശാസ്ത്രപരമായ വ്യത്യാസങ്ങൾ തുറന്നുകാട്ടാൻ ഇത് മതിയാകും. ഭാഗം 1: ഘടകം-ഡ്രൈവൻ (റിയാക്റ്റ് ഹുക്ക് ഫോം + സോഡ്) ഇൻസ്റ്റലേഷൻ npm ഇൻസ്റ്റാൾ react-hook-form zod @hookform/resolvers @tanstack/react-query

സോഡ് സ്കീമ നമുക്ക് Zod സ്കീമയിൽ നിന്ന് ആരംഭിക്കാം, കാരണം അവിടെയാണ് സാധാരണയായി ഫോമിൻ്റെ ആകൃതി സ്ഥാപിക്കുന്നത്. ആദ്യ രണ്ട് ഘട്ടങ്ങൾക്ക് - വ്യക്തിഗത വിശദാംശങ്ങളും ഓർഡർ ഇൻപുട്ടുകളും - എല്ലാം ലളിതമാണ്: ആവശ്യമായ സ്ട്രിംഗുകൾ, മിനിമം ഉള്ള നമ്പറുകൾ, ഒരു enum. നിങ്ങൾ സോപാധിക നിയമങ്ങൾ പ്രകടിപ്പിക്കാൻ ശ്രമിക്കുമ്പോൾ രസകരമായ ഭാഗം ആരംഭിക്കുന്നു.

"zod" ൽ നിന്ന് {z } ഇറക്കുമതി ചെയ്യുക;

കയറ്റുമതി const formSchema = z.object({ firstName: z.string().min(1, "ആവശ്യമാണ്"), ഇമെയിൽ: z.string().email("അസാധുവായ ഇമെയിൽ"), വില: z.number().min(0), അളവ്: z.number().min(1), നികുതിനിരക്ക്: z.ncumber(1), z.enum(["അതെ", "ഇല്ല"]), ഉപയോക്തൃനാമം: z.string().ഓപ്‌ഷണൽ(), പാസ്‌വേഡ്: z.string().ഓപ്ഷണൽ(), സംതൃപ്തി: z.number().min(1).max(5), പോസിറ്റീവ് ഫീഡ്‌ബാക്ക്: z.string().supptional(), improvementalFeedback. ctx) => {if (data.hasAccount === "yes") {if (!data.username) {ctx.addIssue({code: "custom", path: ["username"], സന്ദേശം: "ആവശ്യമാണ്" }); {!data.password. "ഇഷ്‌ടാനുസൃതം", പാത: ["പാസ്‌വേഡ്"], സന്ദേശം: "മിനിമം 6 പ്രതീകങ്ങൾ" });

എങ്കിൽ (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ കോഡ്: "ഇഷ്‌ടാനുസൃതം", പാത: ["പോസിറ്റീവ് ഫീഡ്‌ബാക്ക്"], സന്ദേശം: "നിങ്ങൾക്ക് ഇഷ്ടപ്പെട്ടത് പങ്കിടുക" }); }

എങ്കിൽ (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue({ code: "custom", path:["മെച്ചപ്പെടുത്തൽ ഫീഡ്‌ബാക്ക്"], സന്ദേശം: "എന്താണ് മെച്ചപ്പെടുത്തേണ്ടതെന്ന് ദയവായി ഞങ്ങളോട് പറയുക" }); }});

കയറ്റുമതി തരം FormData = z.infer;

സോഡിൻ്റെ ടൈപ്പ്-ലെവൽ സ്കീമ വസ്തുവിൻ്റെ ആകൃതിയെ വിവരിക്കുന്നതിനാൽ, ഫീൽഡുകൾ പ്രാധാന്യമുള്ളപ്പോൾ നിയന്ത്രിക്കുന്ന നിയമങ്ങളല്ല, ഉപയോക്തൃനാമവും പാസ്‌വേഡും സോപാധികമായി ആവശ്യമാണെങ്കിലും ഓപ്‌ഷണൽ() ആയി ടൈപ്പ് ചെയ്‌തിരിക്കുന്നത് ശ്രദ്ധിക്കുക. സോപാധികമായ ആവശ്യകത സൂപ്പർ റിഫൈനിനുള്ളിൽ ജീവിക്കണം, അത് ആകാരം സാധൂകരിച്ചതിന് ശേഷം പ്രവർത്തിക്കുകയും പൂർണ്ണ ഒബ്‌ജക്റ്റിലേക്ക് ആക്‌സസ് ഉണ്ടായിരിക്കുകയും ചെയ്യുന്നു. ആ വേർപാട് ഒരു ന്യൂനതയല്ല; ടൂൾ രൂപകൽപ്പന ചെയ്‌തിരിക്കുന്നത് ഇതാണ്: സ്കീമ ഘടനയിൽ തന്നെ പ്രകടിപ്പിക്കാൻ കഴിയാത്തപ്പോൾ ക്രോസ്-ഫീൽഡ് ലോജിക് പോകുന്നിടത്താണ് സൂപ്പർ റിഫൈൻ. ഈ സ്കീമ പ്രകടിപ്പിക്കാത്തതും ഇവിടെ ശ്രദ്ധേയമാണ്. ഇതിന് പേജുകളെക്കുറിച്ചുള്ള സങ്കൽപ്പമില്ല, ഏത് ഘട്ടത്തിൽ ഏത് ഫീൽഡുകൾ ദൃശ്യമാകും, നാവിഗേഷൻ എന്ന ആശയവുമില്ല. അതെല്ലാം മറ്റെവിടെയെങ്കിലും ജീവിക്കും. ഫോം ഘടകം

"react-hook-form"-ൽ നിന്ന് {useForm, useWatch} ഇറക്കുമതി ചെയ്യുക;"@hookform/resolvers/zod" എന്നതിൽ നിന്ന് {zodResolver} ഇറക്കുമതി ചെയ്യുക;

const STEPS = ["വിശദാംശങ്ങൾ", "ഓർഡർ", "അക്കൗണ്ട്", "അവലോകനം"];

OrderPayload എന്ന് ടൈപ്പ് ചെയ്യുക = FormData & {ഉപമൊത്തം: നമ്പർ; നികുതി: നമ്പർ; ആകെ: നമ്പർ};

എക്സ്പോർട്ട് ഫംഗ്ഷൻ RHFMultiStepForm() {const [step, setStep] = useState(0);

കോൺസ്റ്റ് മ്യൂട്ടേഷൻ = യൂസ് മ്യൂട്ടേഷൻ({ mutationFn: async (പേലോഡ്: OrderPayload) => { const res = കാത്തിരിക്കുക ("/api/orders", { രീതി: "POST", തലക്കെട്ടുകൾ: { "ഉള്ളടക്ക-തരം": "application/json" }, ബോഡി: JSON.stringify(payload), }); എങ്കിൽ (!res.ok) പുതിയ പിശക് ("സമർപ്പിക്കാൻ പരാജയപ്പെട്ടു"); റിട്ടേൺ res.json(); }, });

const {രജിസ്റ്റർ, നിയന്ത്രണം, ഹാൻഡിൽ സമർപ്പിക്കുക, ഫോംസ്റ്റേറ്റ്: {പിശകുകൾ }, } = useForm({പരിഹാരം: zodResolver(formSchema), defaultValues: { price: 0, quantity: 1, taxRate: 0.1, satisfaction: 3, hasAc,count: }} "No"); const price = useWatch({നിയന്ത്രണം, പേര്: "വില"}); const quantity = useWatch({ control, name: "quantity"}); const taxRate = useWatch({ control, name: "taxRate"}); const hasAccount = useWatch({ control, name: "hasAccount"}); const satisfaction = useWatch({ control, name: "satisfaction"}); const subtotal = useMemo(() => (വില ?? 0) * (അളവ് ?? 1), [വില, അളവ്]); const tax = useMemo(() => subtotal * (taxRate ?? 0), [subtotal, taxRate]); const total = useMemo(() => subtotal + tax, [subtotal, tax]); const onSubmit = (data: FormData) => mutation.mutate({ ...data, subtotal, നികുതി, ആകെ }); const showSubmit = (ഘട്ടം === 2 && ആകെ < 100) || (ഘട്ടം === 3 && ആകെ >= 100)

(

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

{step === 1 && ( <> <തിരഞ്ഞെടുക്കുക {...register ("taxRate}) മൂല്യം} value="0.05">5%

Subtotal: {subtotal}
നികുതി: {tax}
ആകെ: {total}
)}

{step === 2 && ( <>

{hasAccount === "അതെ" && ( <> )}

{സംതൃപ്തി >= 4 && (