Ushbu maqola SurveyJS homiyligida Aksariyat React ishlab chiquvchilari uni hech qachon baland ovozda muhokama qilmasdan baham ko'radigan aqliy model mavjud. Bu shakllar har doim komponentlar bo'lishi kerak. Bu shunday stek degan ma'noni anglatadi:
Mahalliy shtat uchun React Hook shakli (minimal qayta ishlash, ergonomik maydonni ro'yxatdan o'tkazish, imperativ shovqin). Tekshirish uchun zod (kiritish to'g'riligi, chegara tekshiruvi, turdagi xavfsiz tahlil). Backend uchun javob so'rovi: yuborish, qayta urinishlar, keshlash, server bilan sinxronlash va hokazo.
Va ko'pgina shakllar uchun - kirish ekranlaringiz, sozlamalar sahifalaringiz, CRUD modallaringiz - bu juda yaxshi ishlaydi. Har bir qism o'z vazifasini bajaradi, ular toza tuzadilar va siz ilovangizning mahsulotingizni haqiqatda farq qiladigan qismlariga o'tishingiz mumkin. Ammo vaqti-vaqti bilan shakl oldingi javoblarga bog'liq ko'rinish qoidalari yoki uchta maydon bo'ylab kaskad bo'lgan olingan qiymatlar kabi narsalarni to'plashni boshlaydi. Balki o'tkazib yuborilishi yoki ishlayotgan jami asosida ko'rsatilishi kerak bo'lgan butun sahifalar ham bo'lishi mumkin. Birinchi shartni useWatch va inline filiali bilan boshqarasiz, bu yaxshi. Keyin boshqa. Keyin siz Zod sxemangiz odatdagi tarzda ifoda eta olmaydigan o'zaro faoliyat qoidalarini kodlash uchun superRefine-ga murojaat qilyapsiz. Keyin, qadam navigatsiya biznes mantig'ini oqizishni boshlaydi. Bir nuqtada siz o'zingiz yaratgan narsaga qaraysiz va shakl endi UI emasligini tushunasiz. Bu ko'proq qaror qabul qilish jarayoni va komponentlar daraxti aynan siz uni saqlagan joyingizdir. Menimcha, bu erda React-dagi shakllarning aqliy modeli buziladi va bu haqiqatan ham hech kimning aybi emas. RHF + Zod to'plami nima uchun mo'ljallanganligida juda yaxshi. Muammo shundaki, biz uni abstraktsiyalari muammoga to'g'ri keladigan nuqtadan keyin foydalanishni davom ettiramiz, chunki alternativa shakllar haqida butunlay boshqacha fikrlashni talab qiladi. Ushbu maqola ushbu alternativa haqida. Buni ko'rsatish uchun biz bir xil ko'p bosqichli shaklni ikki marta quramiz:
Taqdim etish uchun React Query-ga ulangan React Hook Form + Zod bilan, Shaklni komponentlar daraxti emas, balki oddiy JSON sxemasi sifatida ko'rib chiqadigan SurveyJS bilan.
Xuddi shu talablar, bir xil shartli mantiq, oxirida bir xil API chaqiruvi. Keyin biz ko'chirilgan va nima qolganligini aniq xaritaga kiritamiz va qaysi modeldan qachon va qachon foydalanish kerakligini hal qilishning amaliy usulini ishlab chiqamiz. Biz yaratayotgan shakl:
Bu shakl 4 bosqichli oqimdan foydalanadi: 1-qadam: Tafsilotlar
Ismingiz (majburiy), Elektron pochta (majburiy, yaroqli format).
2-qadam: Buyurtma
Birlik narxi, Miqdori, Soliq stavkasi, Olingan: oraliq jami, soliq, Jami.
3-qadam: Hisob va fikr-mulohaza
Hisobingiz bormi? (Ha/Yo'q) Ha → foydalanuvchi nomi + parol bo'lsa, ikkalasi ham talab qilinadi. Agar Yo'q bo'lsa → elektron pochta 1-bosqichda to'plangan.
Qoniqish darajasi (1–5) Agar ≥ 4 boʻlsa → “Sizga nima yoqdi?” deb soʻrang. Agar ≤ 2 boʻlsa → “Biz nimani yaxshilashimiz mumkin?” deb soʻrang.
4-qadam: Ko'rib chiqish
Faqat jami >= 100 bo'lsa paydo bo'ladi Yakuniy topshirish.
Bu ekstremal emas. Ammo bu me'moriy farqlarni ochish uchun etarli. 1-qism: Komponentga asoslangan (React Hook Form + Zod) O'rnatish npm o'rnatish react-hook-form zod @hookform/resolvers @tanstack/react-query
Zod sxemasi Keling, Zod sxemasidan boshlaylik, chunki bu erda odatda shakl shakli o'rnatiladi. Dastlabki ikki bosqichda - shaxsiy ma'lumotlar va buyurtma ma'lumotlari - hamma narsa oddiy: kerakli satrlar, minimal raqamlar va raqamlar. Qiziqarli qism shartli qoidalarni ifodalashga harakat qilganda boshlanadi.
"zod" dan { z } import qilish;
eksport const formSchema = z.object({ firstName: z.string().min(1, "Zarur"), email: z.string().email("Noto'g'ri email"), narx: z.number().min(0), miqdor: z.number().min(1), taxRate: z.number(), hasAccount(),"Yo'q username[])," z.string().ixtiyoriy(), parol: z.string().ixtiyoriy(), qoniqish: z.number().min(1).maks(5), pozitivFeedback: z.string().ixtiyoriy(), improvementFeedback: z.string().ixtiyoriy(),}).superRefine((maʼlumotlar, ctxda) ="Y {ma'lumotlar, ctxda ="A {agar}, agar (count) ="s. (!data.username) { ctx.addIssue({ kod: "custom", path: ["foydalanuvchi nomi"], xabar: "Talab qilinadi" }); }
agar (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({kod: "custom", path: ["positiveFeedback"], xabar: "Iltimos, sizga yoqqan narsani baham ko'ring" }); }
agar (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue ({ kod: "custom", yo'l:["improvementFeedback"], xabar: "Iltimos, bizga nimani yaxshilash kerakligini ayting" }); }});
eksport turi FormData = z.infer
E'tibor bering, foydalanuvchi nomi va parol shartli ravishda talab qilingan bo'lsa ham, ixtiyoriy() sifatida kiritiladi, chunki Zod turi darajasidagi sxemasi maydonlar muhim bo'lgan vaqtni tartibga soluvchi qoidalarni emas, balki ob'ekt shaklini tavsiflaydi. Shartli talab superRefine ichida bo'lishi kerak, u shakl tasdiqlangandan keyin ishlaydi va to'liq ob'ektga kirish huquqiga ega. Bu ajralish kamchilik emas; bu vosita aynan nima uchun mo'ljallangan: superRefine - bu sxema tuzilishining o'zida ifodalash mumkin bo'lmaganda o'zaro faoliyat mantiqqa o'tadigan joy. Bu erda ham diqqatga sazovor narsa, bu sxema nimani ifodalamaydi. Unda sahifalar tushunchasi, qaysi maydonlar qaysi nuqtada ko‘rinib turishi va navigatsiya tushunchasi yo‘q. Bularning barchasi boshqa joyda yashaydi. Shakl komponenti
import { useForm, useWatch } ni "react-hook-form"dan;import { zodResolver } from "@hookform/resolvers/zod";import { useMutation} from "@tanstack/react-query";import { useState, useMemo} from "react"; import { formSchema, type ".";
const STEPS = ["tafsilotlar", "buyurtma", "hisob", "ko'rib chiqish"];
turi OrderPayload = FormData & {oraliq jami: raqam; soliq: raqam; jami: soni };
eksport funksiyasi RHFMultiStepForm() { const [qadam, setStep] = useState(0);
const mutatsiya = useMutation({ mutationFn: asinxron (foydali yuk: OrderPayload) => { const res = olishni kuting ("/api/orders", { usul: "POST", sarlavhalar: { "Content-Type": "application/json" }, Tana: JSON.stringify (foydali yuk), }); agar (!res.ok) yangi Xato ("Yuborish muvaffaqiyatsiz tugadi"); qaytish res.json(); }, });
const { register, control, handleSubmit, formState: { xatolar }, } = useForm
qaytish (
);}Pen SurveyJS-03-RHF ga qarang [forked] tomonidan oltinchi yo'q. Bu erda juda ko'p narsa sodir bo'lmoqda va narsalar qayerda tugaganini payqash uchun sekinlashishga arziydi.
Olingan qiymatlar - subjami, soliq, jami - komponentda useWatch va useMemo orqali hisoblab chiqiladi, chunki ular jonli maydon qiymatlariga bog'liq va ular uchun boshqa tabiiy joy yo'q. Foydalanuvchi nomi, parol, ijobiy Feedback va yaxshilash uchun koʻrinish qoidalari JSX da inline shartlar sifatida ishlaydi. Bosqichni o'tkazib yuborish mantig'i - ko'rib chiqish sahifasi faqat jami >= 100 bo'lganda paydo bo'ladi - showSubmit o'zgaruvchisiga va 3-bosqichdagi render shartiga kiritilgan. Navigatsiyaning o'zi biz qo'lda oshirayotgan useState hisoblagichidir. React Query qayta urinishlar, keshlash va bekor qilish bilan shug'ullanadi. Shakl faqat tasdiqlangan ma'lumotlar bilan mutatsiya.mutatsiyani chaqiradi.
Bularning hech biri noto'g'ri emas, o'z-o'zidan. Bu hali ham idiomatik Reaksiya bo'lib, RHF qanday izolyatsiya qilgani qayta ko'rsatilishi tufayli komponent juda samarali. Ammo agar siz buni yozmagan odamga topshirsangiz va ulardan ko'rib chiqish sahifasi qanday sharoitlarda paydo bo'lishini tushuntirishni so'rasangiz, ular bir satrda aytilishi mumkin bo'lgan qoidani qayta tiklash uchun showSubmit, 3-bosqichni ko'rsatish sharti va navbat tugmasi mantig'ini - uchta alohida joyni kuzatishi kerak bo'ladi. Shakl ishlaydi, ha, lekin xatti-harakatlar tizim sifatida tekshirib bo'lmaydi. Buni aqliy ravishda bajarish kerak. Eng muhimi, uni o'zgartirish muhandislik ishtirokini talab qiladi. Ko'rib chiqish bosqichi paydo bo'lganda sozlash kabi kichik sozlash ham komponentni tahrirlash, tekshirishni yangilash, tortib olish so'rovini ochish, ko'rib chiqishni kutish va qayta joylashtirishni anglatadi. 2-qism: Sxemaga asoslangan (SurveyJS) Endi sxema yordamida bir xil oqimni quramiz. O'rnatish npm o'rnating survey-core survey-react-ui @tanstack/react-query
survey-core. MIT litsenziyasiga ega platformadan mustaqil ish vaqti mexanizmi, SurveyJS formalarini ko'rsatishni quvvatlantiradi - bu biz uchun muhim qism. U JSON sxemasini oladi, undan ichki modelni yaratadi va React komponentingizda aks holda yashashi mumkin bo'lgan hamma narsani boshqaradi: ko'rinish ifodalarini baholash, olingan qiymatlarni hisoblash, sahifa holatini boshqarish, tekshirishni kuzatish va qaysi sahifalar aslida ko'rsatilgan bo'lsa, "to'liq" nimani anglatishini hal qilish.
survey-react-uiUshbu modelni React bilan bog'laydigan UI/renderlash qatlami. Bu, aslida, dvigatel holati o'zgarganda qayta ko'rsatiladigan
Birgalikda ular sizga boshqaruv oqimining bir qatorini yozmasdan to'liq funktsional, ko'p sahifali shakl ish vaqtini beradi. Sxema formatining o'zi, yuqorida aytib o'tilganidek, shunchaki JSON - DSL yoki hech qanday mulkiy narsa yo'q. Siz uni qatorga kiritishingiz, fayldan import qilishingiz, APIʼdan olishingiz yoki maʼlumotlar bazasi ustunida saqlashingiz va ish vaqtida namlashingiz mumkin. Ma'lumotlar bilan bir xil shakl Mana bir xil shakl, bu safar JSON obyekti sifatida ifodalangan. Sxema hamma narsani belgilaydi: tuzilma, tekshirish, ko'rinish qoidalari, olingan hisoblar, sahifalarni navigatsiya qilish - va uni ish vaqtida baholaydigan Modelga topshiradi. Bu to'liq qanday ko'rinishga ega:
eksport const surveySchema = { sarlavha: "Buyurtma oqimi", showProgressBar: "yuqori", sahifalar: [ { nomi: "tafsilotlar", elementlar: [ { turi: "matn", nom: "firstName", isTalab: rost }, { turi: "matn", nomi: "email", inputType: "email", isTalab: "truziya: identifikatori", email" }] } ] }, { nomi: "buyurtma", elementlar: [ { turi: "matn", nom: "narx", inputType: "raqam", defaultValue: 0 }, { turi: "matn", nom: "miqdor", inputType: "raqam", defaultValue: 1 }, { turi: "ochiladigan",nom: "taxRate", defaultValue: 0,1, tanlovlar: [ {qiymat: 0,05, matn: "5%" }, {qiymat: 0,1, matn: "10%" }, {qiymat: 0,15, matn: "15%" } ] }, {turi: "ifoda", nomi: "{anti qiymat:" {}turi," "ifoda", ism: "soliq", ifoda: "{subjami} {taxRate}" }, { turi: "ifoda", nomi: "jami", ifoda: "{subjami} + {tax}" } ] }, { nomi: "hisob", elementlar: [ {turi: "radioguruh", nomi: "hasAccount", ["] turi ":" {":" {Tanlovlar", nom: "foydalanuvchi nomi", visibleIf: "{hasAccount} = 'Ha'", isRequired: true }, { type: "matn", name: "password", inputType: "password", visibleIf: "{hasAccount} = 'Ha'", isRequired: true, validators:ext: [{hasAccount}: minut ":" 6-minng, matn "turi" belgilar" }] }, { turi: "reyting", ism: "qoniqish", rateMin: 1, rateMax: 5 }, { turi: "sharh", nomi: "pozitiv Feedback", visibleIf: "{qoniqish} >= 4" }, { turi: "sharh", ism: "improvementFeed" "{satisfaction:" <}" ] }, { name: "review", visibleIf: "{jami} >= 100", elementlar: [] } ]};
Buni RHF versiyasi bilan bir lahzaga solishtiring.
Shartli ravishda talab qilinadigan foydalanuvchi nomi va parolni talab qiladigan superRefine bloki yo'qoldi. visibleIf: "{hasAccount} = "Ha"" isRequired bilan birlashtirilgan: true ikkala muammoni birgalikda, ularni topishni kutgan maydonning o'zida hal qiladi. Subjam, soliq va jami hisoblangan useWatch + useMemo zanjiri bir-biriga nom bilan murojaat qiluvchi uchta ifoda maydoni bilan almashtiriladi. RHF versiyasida faqat showSubmit orqali kuzatish orqali qayta tiklanadigan ko'rib chiqish sahifasi holati, 3-bosqich render bo'limi. Va nihoyat, navbat tugmasi mantig'i sahifa ob'ektidagi yagona visibleIf xususiyatidir.
Xuddi shu mantiq bor. Shunchaki, sxema unga komponent bo‘ylab tarqalishdan ko‘ra, alohida ko‘rinadigan joyda yashash joyini beradi. Shuni ham yodda tutingki, sxema oraliq jami, soliq va jami uchun "ifoda" turidan foydalanadi. Ifoda faqat o'qish uchun mo'ljallangan va asosan hisoblangan qiymatlarni ko'rsatish uchun ishlatiladi. SurveyJS shuningdek, statik kontent uchun "html" turini qo'llab-quvvatlaydi, ammo hisoblangan qiymatlar uchun ifoda to'g'ri tanlovdir. Endi reaktsiya tomoni uchun. Renderlash va topshirish Juda oddiy. Wire onComplete-ni API-ga xuddi shu tarzda - useMutation yoki oddiy olib kirish orqali:
import { useState, useEffect, useRef} ni "react"dan;import { useMutation } from "@tanstack/react-query";import { Model} from "survey-core";import { Survey} from "survey-react-ui";import "survey-core/survey-core.css";
eksport funktsiyasi SurveyForm() { const [model] = useState(() => yangi Model(surveySchema));
const mutatsiya = useMutation({ mutationFn: async (ma'lumotlar) => { const res = olishni kuting ("/api/orders", { usul: "POST", sarlavhalar: { "Content-Type": "application/json" }, tanasi: JSON.stringify (ma'lumotlar), }); agar (!res.ok) yangi Xato ("Yuborish muvaffaqiyatsiz tugadi"); qaytish res.json(); }, });
const mutationRef = useRef(mutatsiya); mutationRef.current = mutatsiya; useEffect(() => { const handler = (sender) => mutationRef.current.mutate(sender.data); model.onComplete.add(handler); return () => model.onComplete.remove(handler);}, [model]); // ref ishlov beruvchini har bir renderni qayta ro'yxatdan o'tkazishdan qochadi (mutatsion ob'ekt identifikatori o'zgaradi)
qaytish (
<>
Pen SurveyJS-03-SurveyJS [forked] tomonidan sixthextinction ga qarang.
onComplete foydalanuvchi oxirgi ko'rinadigan sahifaning oxiriga yetganda yonadi. Shunday qilib, agar jami hech qachon 100 dan oshmasa va ko'rib chiqish sahifasi o'tkazib yuborilsa, u hali ham to'g'ri yonadi, chunki SurveyJS "oxirgi sahifa" nimani anglatishini hal qilishdan oldin ko'rinishni baholaydi. Keyin, sender.data birinchi darajali maydonlar sifatida hisoblangan qiymatlar (subjami, soliq, jami) bilan birga barcha javoblarni o'z ichiga oladi, shuning uchun API foydali yuki RHF versiyasi onSubmit-da qo'lda yig'ilgan bilan bir xil bo'ladi. ThemutationRef namunasi har bir renderda oʻzgarib turadigan qiymat ustidan barqaror hodisa ishlovchisi kerak boʻlgan istalgan joyda erisha oladigan namunadir – bu haqda SurveyJS-ga xos hech narsa yoʻq.
React komponenti endi hech qanday biznes mantiqini o'z ichiga olmaydi. UseWatch, shartli JSX, qadam hisoblagichi, useMemo zanjiri, superRefine yo'q. React o'zi yaxshi bo'lgan narsani qilmoqda: komponentni ko'rsatish va uni API chaqiruviga ulash. Reaksiyadan nima o'tdi?
Xavotir RHF to'plami SurveyJS Ko'rinish JSX filiallari visibleIf Olingan qiymatlar useWatch / useMemo ifoda Kross-maydon qoidalari super tozalash Sxema shartlari Navigatsiya qadam holati Page visibleIf Qoidalarning joylashuvi Fayllar bo'ylab taqsimlangan Sxemada markazlashtirilgan
React-da qoladi - bu tartib, uslub, jo'natish simlari va ilovalar integratsiyasi, ya'ni React aslida uchun mo'ljallangan. Qolgan hamma narsa sxemaga ko'chirildi va sxema shunchaki JSON ob'ekti bo'lgani uchun uni ma'lumotlar bazasida saqlash, ilova kodingizdan mustaqil ravishda versiyalash yoki joylashtirishni talab qilmasdan ichki asboblar orqali tahrirlash mumkin. Ko'rib chiqish sahifasini ishga tushiradigan chegarani o'zgartirishi kerak bo'lgan mahsulot menejeri buni komponentga tegmasdan amalga oshirishi mumkin. Shakl xatti-harakatlari tez-tez rivojlanib turadigan va har doim ham muhandislar tomonidan boshqarilmaydigan jamoalar uchun bu sezilarli operatsion farqdir. Har bir yondashuvdan qachon foydalanish kerak? Mana men uchun ishlaydigan yaxshi qoida: shaklni butunlay o'chirib tashlashni tasavvur qiling. Siz nimani yo'qotasiz?
Agar bu ekranlar bo'lsa, siz komponentlarga asoslangan shakllarni xohlaysiz. Haqiqiy qarorlarni kodlaydigan chegaralar, tarmoqlanish qoidalari va shartli talablar kabi biznes mantig'i bo'lsa, sizga sxema mexanizmi kerak bo'ladi.
Xuddi shunday, agar sizning yo'lingizdagi o'zgarishlar asosan teglar, maydonlar va tartib bilan bog'liq bo'lsa, RHF sizga yaxshi xizmat qiladi. Agar ular sizning operatsiyalaringiz yoki yuridik guruhingiz seshanba kuni tushdan keyin chipta topshirmasdan o'zgartirishi kerak bo'lgan shartlar, natijalar va qoidalar haqida bo'lsa, SurveyJS bilan sxema modeli yanada to'g'ri keladi. Bu ikki yondashuv aslida bir-biri bilan raqobatlashmaydi. Ular muammolarning turli sinflarini ko'rib chiqadilar va oldini olish kerak bo'lgan xato - abstraksiyani mantiqning og'irligiga mos kelmaslik - qoidalar tizimini komponent sifatida ko'rib chiqish, chunki bu tanish vosita yoki siyosat mexanizmiga murojaat qilish, chunki shakl uch bosqichga o'sib, shartli maydonga ega bo'ldi. Biz bu erda qurgan shakl ataylab chegaraga yaqin joylashgan, farqni ochib beradigan darajada murakkab, ammo taqqoslash soxta bo'lib tuyuladigan darajada ekstremal emas. Kod bazangizda noqulay bo'lib qolgan ko'pgina haqiqiy shakllar, ehtimol, xuddi shu chegaraga yaqin joylashgan va savol, odatda, kimdir ularning aslida nima ekanligini aytdimi yoki yo'qmi. Quyidagi hollarda React Hook Form + Zod dan foydalaning:
Shakllar CRUDga yo'naltirilgan; Mantiq sayoz va UI tomonidan boshqariladi; Muhandislar barcha xatti-harakatlarga ega; Backend haqiqat manbai bo'lib qoladi.
SurveyJS-dan quyidagi hollarda foydalaning:
Shakllar biznes qarorlarini kodlaydi; Qoidalar foydalanuvchi interfeysidan mustaqil ravishda rivojlanadi; Mantiq ko'rinadigan, tekshiriladigan yoki versiyalashtirilgan bo'lishi kerak; Muhandis bo'lmaganlar xatti-harakatlarga ta'sir qiladi; Xuddi shu shakl bir nechta frontendlarda ishlashi kerak.