Ин мақола аз ҷониби SurveyJS сарпарастӣ шудааст Модели равонӣ вуҷуд дорад, ки аксари таҳиягарони React бидуни ҳеҷ гоҳ онро бо овози баланд муҳокима мекунанд. Ин шаклҳо бояд ҳамеша ҷузъҳо бошанд. Ин маънои онро дорад, ки стек ба монанди:

Шакли Hook React барои давлати маҳаллӣ (ҳадди ақали такрорӣ, бақайдгирии майдони эргономикӣ, ҳамкории императивӣ). Zod барои тасдиқ (дурустии вуруд, санҷиши сарҳад, таҳлили бехатарии навъи). React Query барои пуштибонӣ: пешниҳод, кӯшишҳои такрорӣ, кэш, ҳамоҳангсозии сервер ва ғайра.

Ва барои аксарияти шаклҳо - экранҳои воридшавии шумо, саҳифаҳои танзимоти шумо, модальҳои CRUD - ин воқеан хуб кор мекунад. Ҳар як порча кори худро иҷро мекунад, онҳо тоза эҷод мекунанд ва шумо метавонед ба қисмҳои замимаатон гузаред, ки воқеан маҳсулоти шуморо фарқ мекунанд. Аммо ҳар як вақт, форма ба ҷамъ кардани чизҳое оғоз мекунад, ба монанди қоидаҳои намоён, ки аз ҷавобҳои қаблӣ вобастаанд ё арзишҳои ҳосилшуда, ки тавассути се майдон фаро гирифта шудаанд. Шояд ҳатто тамоми саҳифаҳое, ки бояд дар асоси ҷамъи ҷорӣ гузаронида шаванд ё нишон дода шаванд. Шумо шарти аввалро бо useWatch ва шохаи inline идора мекунед, ки ин хуб аст. Баъд дигар. Пас шумо ба superRefine мерасед, то қоидаҳои байнисоҳаро рамзгузорӣ кунад, ки схемаи Zod-и шумо ба таври муқаррарӣ ифода карда наметавонад. Сипас, паймоиши қадам ба ихроҷи мантиқи тиҷорат оғоз мекунад. Дар баъзе мавридҳо, шумо ба он чизе, ки шумо сохтаед, назар мекунед ва дарк мекунед, ки шакл дигар воқеан UI нест. Ин бештар як раванди тасмимгирӣ аст ва дарахти ҷузъӣ ҳамон ҷоест, ки шумо онро нигоҳ доштаед. Ин аст, ки ман фикр мекунам, ки модели равонии шаклҳо дар React вайрон мешавад ва ин дар ҳақиқат ҳеҷ кас айбдор нест. Стеки RHF + Zod дар он чизе, ки барои он тарҳрезӣ шудааст, аъло аст. Масъала дар он аст, ки мо майл дорем, ки онро то он даме, ки абстраксияҳои он ба мушкилот мувофиқат мекунанд, истифода мебарем, зеро алтернатива тарзи дигари тафаккурро дар бораи шаклҳо комилан талаб мекунад. Ин мақола дар бораи он алтернатива аст. Барои нишон додани ин, мо ҳамон як шакли бисёрқадамро ду маротиба месозем:

Бо React Hook Form + Zod ба React Query барои пешниҳод пайваст шудааст, Бо SurveyJS, ки шаклро ҳамчун маълумот баррасӣ мекунад - схемаи оддии JSON - на дарахти компонент.

Талаботи якхела, ҳамон мантиқи шартӣ, ҳамон занги API дар охири. Сипас, мо аниқ харитаи чизеро, ки кӯчида ва чӣ боқӣ мондааст, тартиб медиҳем ва роҳи амалиеро муайян мекунем, ки кадом моделро кай ва кай истифода бурдан лозим аст. Формае, ки мо сохта истодаем:

Ин шакл ҷараёни 4-қадамро истифода мебарад: Қадами 1: Тафсилот

Номи аввал (ҳатмӣ), Почтаи электронӣ (ҳатмӣ, формати дуруст).

Қадами 2: Фармоиш

Нархи воҳид, Миқдор, Меъёри андоз, Баровард: Ҷамъбаст, андоз, Ҳамагӣ.

Қадами 3: Ҳисоб ва фикру мулоҳиза

Оё шумо ҳисоб доред? (Ҳа/Не) Агар Ҳа → номи корбар + парол, ҳарду лозиманд. Агар Не → почтаи электронӣ аллакай дар қадами 1 ҷамъоварӣ шудааст.

Рейтинги қаноатмандӣ (1–5) Агар ≥ 4 → пурсед "Чӣ ба шумо писанд омад?" Агар ≤ 2 → пурсед, ки "Мо чиро беҳтар карда метавонем?"

Қадами 4: Барраси

Танҳо дар сурати ҷамъ >= 100 пайдо мешавад Пешниҳоди ниҳоӣ.

Ин шадид нест. Аммо барои фош кардани фарқиятҳои меъморӣ кофӣ аст. Қисми 1: Компонентҳо асосёфта (Формаи Hook React + Zod) Насбкунӣ npm насб кардани react-hook-form zod @hookform/resolvers @tanstack/react-query

Схемаи Зод Биёед бо схемаи Zod оғоз кунем, зеро одатан дар он ҷо шакли шакл муқаррар карда мешавад. Барои ду қадами аввал - тафсилоти шахсӣ ва вурудоти фармоиш - ҳама чиз осон аст: сатрҳои зарурӣ, рақамҳо бо ҳадди аққал ва рақам. Қисми ҷолиб вақте оғоз мешавад, ки шумо кӯшиш мекунед, ки қоидаҳои шартиро баён кунед.

воридоти { z } аз "zod";

содироти const formSchema = z.object({ firstName: z.string().min(1, "Талаб карда мешавад"), почтаи электронӣ: z.string().email("Почтаи беэътибор"), нарх: z.number().min(0), микдор: z.number().min(1), taxRate: z.number(), hasAccount(), name user(), "z":" z.string().optional(), гузарвожа: z.string().optional(), қаноатмандӣ: z.number().min(1).макс(5), мусбӣFeedback: z.string().ixtiyari(), improvementFeedback: z.string().optional(),}).superRefine((маълумот, ctxda==)(маълумот, ctxda=agar=s.A {agar count) =" {A. (!data.username) { ctx.addIssue({ code: "custom", path: ["username"], message: "Талаб карда мешавад" }); }

if (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ код: "custom", path: ["positiveFeedback"], паём: "Лутфан он чизеро, ки ба шумо маъқул буд, мубодила кунед" }); }

агар (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue ({ код: "муштарӣ", роҳ:["improvementFeedback"], паём: "Лутфан, ба мо бигӯед, ки чӣ бояд беҳтар шавад" }); }});

навъи содирот FormData = z.infer;

Аҳамият диҳед, ки номи корбар ва парол ҳамчун ихтиёрӣ () чоп карда мешаванд, гарчанде ки онҳо шартан талаб карда мешаванд, зеро схемаи сатҳи навъи Zod шакли объектро тавсиф мекунад, на қоидаҳои танзимкунандаи вақте ки майдонҳо муҳиманд. Талаботи шартӣ бояд дар дохили superRefine зиндагӣ кунад, ки пас аз тасдиқи шакл кор мекунад ва ба объекти пурра дастрасӣ дорад. Ин ҷудоӣ камбудие нест; ин маҳз ҳамон чизест, ки асбоб барои он тарҳрезӣ шудааст: superRefine он ҷоест, ки мантиқи байнисоҳавӣ ҷойгир аст, вақте ки онро дар худи сохтори схема ифода кардан мумкин нест. Он чизе, ки дар ин ҷо низ ҷолиб аст, он чизест, ки ин схема ифода намекунад. Он мафҳуми саҳифаҳо надорад, мафҳуми он, ки кадом майдонҳо дар кадом нуқта намоён мешаванд ва мафҳуми навигатсия вуҷуд надорад. Ҳамаи ин дар ҷои дигар зиндагӣ хоҳад кард. Компоненти форма

import { useForm, useWatch } аз "react-hook-form";import { zodResolver } аз "@hookform/resolvers/zod";import { useMutation } аз "@tanstack/react-query";import { useState, useMemo } аз "react"; import { formSchema} аз FormSchema, навъи ";";

const STEPS = ["тафсилот", "фармоиш", "ҳисоб", "баррасӣ"];

навъи OrderPayload = FormData & { subtotal: рақам; андоз: рақам; ҷамъ: адад };

Функсияи содироти RHFMultiStepForm () { const [қадам, setStep] = useState (0);

const мутатсия = useMutation({ mutationFn: асинхронӣ (борбор: OrderPayload) => { const res = интизори гирифтани овардан ("/api/orders", { усул: "POST", сарлавҳаҳо: { "Content-Type": "application/json" }, бадан: JSON.stringify (борбори), }); агар (!res.ok) партоед Хатои нав("Фарол кардан муяссар нашуд"); баргардонидани res.json(); }, });

const { регистр, назорат, handleSubmit, formState: { хатоҳо }, } = useForm({solver: zodResolver(formSchema), defaultValues: {нарх: 0, микдор: 1, taxRate: 0.1, қаноатмандӣ: 3, hasAccount: "Не", },}); const нархи = useWatch({ назорат, ном: "нарх" }); миқдори const = useWatch ({ назорат, ном: "микдор" }); const taxRate = useWatch ({ назорат, ном: "taxRate" }); const hasAccount = useWatch ({ назорат, ном: "hasAccount" }); const қаноатмандӣ = useWatch ({ назорат, ном: "қаноатмандӣ" }); const subtotal = useMemo(() => (нарх ?? 0) * (микдор ?? 1), [нарх, микдор]); андоз const = useMemo(() => зермаҷмӯӣ * (taxRate ?? 0), [маҷмӯи зермаҷмӯӣ, taxRate]); const total = useMemo(() => зермаҷмӯӣ + андоз, [маҷмӯа, андоз]); const onSubmit = (маълумот: FormData) => mutation.mutate ({ ...маълумот, ҷамъи миёна, андоз, ҷамъ }); const showSubmit = (қадам === 2 && ҷамъ < 100) || (қадам === 3 && ҷамъ >= 100)

бозгашт (

{қадам === 0 && ( <> <ворид {...register("firstName")} placeholder="Номи аввал" /> <ворид {...register("email")} placeholder="Email" /> )}

{қадам === 1 && ( <> <навъи вуруд = "рақам" {...қайдгирӣ("нарх", { valueAsNumber: ҳақиқӣ })} /> <навъи вуруд = "рақам" {...қайдгирӣ("микдор", { valueAsNumber: ҳақиқӣ })} /> <интихоб кунед {...қайдгирӣ("taxRate", { арзиши)}} value="0,05">5%

Subtotal: {subtotal}
Андоз: {tax}
Ҷамъ: {ҳамагӣ}
)}

{қадам === 2 && ( <> <ро интихоб кунед {...register("hasAccount")}>

{hasAccount === "Ҳа" && ( <> <ворид {...register("username")} placeholder="Номи корбар" /> <ворид {...register("парол")} placeholder="Парол" /> )}

<навъи вуруд = "рақам" {...қайдгирӣ("қаноатмандӣ", { valueAsNumber: ҳақиқӣ })} />

{қаноатмандӣ >= 4 && (