Бул макала SurveyJS тарабынан каржыланган Көпчүлүк React иштеп чыгуучулары аны эч качан катуу талкуулабастан бөлүшө турган психикалык модель бар. Бул формалар ар дайым компоненттер болушу керек. Бул стек дегенди билдирет:
Жергиликтүү штат үчүн React Hook формасы (минималдуу кайра көрсөтүү, эргономикалык талааны каттоо, императивдик өз ара аракеттенүү). Валидация үчүн зод (киргизүүнүн тууралыгы, чек араны текшерүү, типтин коопсуз талдоосу). Backend үчүн React Query: тапшыруу, кайра аракет кылуу, кэштөө, серверди синхрондоштуруу ж.б.у.с.
Ал эми формалардын басымдуу көпчүлүгү үчүн – сиздин кирүү экрандарыңыз, жөндөө беттериңиз, CRUD модалдарыңыз – бул абдан жакшы иштейт. Ар бир бөлүгү өз милдетин аткарат, алар таза түзүшөт жана сиз колдонмоңуздун продуктуну айырмалай турган бөлүктөрүнө өтө аласыз. Бирок маал-маалы менен форма мурунку жоопторго көз каранды көрүнүү эрежелери же үч талаа аркылуу каскаддан өткөн алынган баалуулуктар сыяктуу нерселерди топтой баштайт. Мүмкүн, атүгүл бүтүндөй барактарды өткөрүп жиберүү же иштеп жаткан сумманын негизинде көрсөтүү керек. Биринчи шартты useWatch жана сап бутагы менен иштетесиз, бул жакшы. Андан кийин башка. Андан кийин Zod схемаңыз кадимки жол менен билдире албаган кайчылаш талаа эрежелерин коддоо үчүн superRefineге жетип жатасыз. Андан кийин, кадам багыттоо бизнес логикасын агып баштайт. Кайсы бир учурда, сиз курган нерсеңизди карап, форма мындан ары UI эмес экенин түшүнөсүз. Бул чечим кабыл алуу процесси жана компонент дарагы сиз аны сактаган жерде. Бул жерде менимче, React'теги формалардын психикалык модели бузулат жана бул чындыгында эч кимдин күнөөсү эмес. RHF + Zod стек ал үчүн иштелип чыккан мыкты. Маселе, биз аны анын абстракциялары көйгөйгө дал келген чекитке чейин колдоно беребиз, анткени альтернатива формалар жөнүндө башкача ой жүгүртүүнү талап кылат. Бул макала ошол альтернатива жөнүндө. Муну көрсөтүү үчүн, биз бир эле көп баскычтуу форманы эки жолу курабыз:
React Hook Form + Zod менен React Query тапшыруу үчүн, Форманы компонент катары эмес, жөнөкөй JSON схемасы катары караган SurveyJS менен.
Ошол эле талаптар, ошол эле шарттуу логика, аягында ошол эле API чалуу. Андан кийин биз эмне көчүп, эмне калганын так картага түшүрөбүз жана кайсы моделди жана качан колдонуу керектигин чечүүнүн практикалык жолун сунуштайбыз. Биз түзүп жаткан форма:
Бул форма 4 кадамдуу агымды колдонот: 1-кадам: чоо-жайы
Аты-жөнү (талап кылынат), Электрондук почта (талап кылынат, жарактуу формат).
2-кадам: Заказ
бирдик баасы, Саны, Салык ставкасы, Алынган: Аралык сумма, салык, Бардыгы.
3-кадам: Каттоо эсеби жана пикир
Сиздин аккаунтуңуз барбы? (Ооба/Жок) Ооба → колдонуучу аты + сырсөз болсо, экөө тең талап кылынат. Эгерде Жок → электрондук почта 1-кадамда чогултулган.
Канааттануу рейтинги (1–5) Эгерде ≥ 4 → "Сизге эмне жакты?" деп сураңыз. Эгерде ≤ 2 → "Эмнени жакшырта алабыз?" деп сураңыз.
4-кадам: карап чыгуу
Жалпы >= 100 болсо гана көрүнөт Акыркы тапшыруу.
Бул экстремалдуу эмес. Бирок бул архитектуралык айырмачылыктарды ачуу үчүн жетиштүү. 1-бөлүк: Компонентке негизделген (React Hook Form + Zod) Орнотуу npm орнотуу react-hook-form zod @hookform/resolvers @tanstack/react-query
Zod схемасы Зод схемасынан баштайлы, анткени форманын формасы көбүнчө ошол жерде орнойт. Алгачкы эки кадам үчүн - жеке маалыматтар жана буйрутма киргизүү - баары жөнөкөй: талап кылынган саптар, минималдуу сандар жана энум. Кызыктуу бөлүгү шарттуу эрежелерди айтууга аракет кылганда башталат.
"zod"дан { z } импорттоо;
export const formSchema = z.object({ firstName: z.string().min(1, "Талап кылынган"), email: z.string().email("Жарамсыз электрондук почта"), баасы: z.number().min(0), саны: z.number().min(1), taxRate: z.number(), hasAccount(), username(]), "Yok":" z.string().optional(), сырсөз: z.string().optional(), канааттануу: z.number().min(1).max(5), оң пикир: z.string().optional(), improvementFeedback: z.string().optional(),}).superRefine((дата, ctxda) ="s. (!data.username) { ctx.addIssue({код: "колдонуучунун аты", жол: ["колдонуучунун аты"], билдирүү: "Талап кылынат" }); }
if (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({код: "адат", жол: ["positiveFeedback"], билдирүү: "Сизге жаккан нерсени бөлүшүңүз" }); }
if (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue({код: "ыңгайлаштырылган", жол:["improvementFeedback"], билдирүү: "Бизге эмнени жакшыртуу керектигин айтыңыз"}); }});
экспорт түрү FormData = z.infer
Колдонуучунун аты жана сырсөз шарттуу түрдө талап кылынса да, кошумча() катары терилгенине көңүл буруңуз, анткени Zodдун тип деңгээлиндеги схемасы талаалар маанилүү болгон учурда башкарган эрежелерди эмес, объекттин формасын сүрөттөйт. Шарттуу талап форма текшерилгенден кийин иштей турган жана толук объектке кирүү мүмкүнчүлүгү бар superRefine ичинде жашашы керек. Бул бөлүнүү кемчилик эмес; бул жөн гана курал эмне үчүн иштелип чыккан: superRefine - бул схема түзүмүндө чагылдырылбаганда кайчылаш талаа логикасы кайда барат. Бул жерде дагы бир маанилүү нерсе, бул схема эмнени билдирбейт. Анын беттер түшүнүгү жок, кайсы талаалар кайсы жерде көрүнөрү жана навигация түшүнүгү жок. Мунун баары башка жерде жашайт. Форма компоненти
"react-hook-form"дан { useForm, useWatch } импорттоо; "@hookform/resolvers/zod"дан { zodResolver } импорттоо; "@tanstack/react-query"ден { useMutation } импорттоо; "реакциядан" { useState, useMemo } импорттоо; Import { formSchema, "."
const STEPS = ["деталдар", "заказ", "эсеп", "карап чыгуу"];
түрү OrderPayload = FormData & {аралык: саны; салык: саны; жалпы: саны };
экспорт функциясы RHFMultiStepForm() { const [кадам, setStep] = useState(0);
const мутация = useMutation({ mutationFn: асинхрондук (пайдалуу жүк: OrderPayload) => { const res = күтүү алып келүү("/api/orders", { ыкма: "POST", аталыштар: { "Content-Type": "application/json" }, дене: JSON.stringify(пайдалуу жүк), }); if (!res.ok) throw new Error("Failed to submit"); return res.json(); }, });
const { регистр, контроль, handleSubmit, formState: { каталар }, } = useForm
return (
);}Pen SurveyJS-03-RHF караңыз [айрыкча] менен sixthextinction. Бул жерде абдан көп болуп жатат, жана нерселердин кайда аяктаганын байкаш үчүн жайлоо керек.
Алынган маанилер - кошумча сумма, салык, жалпы - компонентте useWatch жана useMemo аркылуу эсептелет, анткени алар талаанын жандуу маанилеринен көз каранды жана алар үчүн башка табигый жер жок. Колдонуучунун аты, сырсөз, позитивдуу пикир жана жакшыртуу боюнча көрүнүү эрежелери JSX ичинде саптык шарттар катары жашайт. Кадамды өткөрүп жиберүү логикасы — карап чыгуу барагы жалпы >= 100 болгондо гана пайда болот — showSubmit өзгөрмөсүнө жана 3-кадамдагы көрсөтүү шартына кыстарылган. Навигациянын өзү жөн гана биз кол менен көбөйтүп жаткан useState эсептегич. React Query кайталап аракеттерди, кэштөө жана жараксыз деп эсептейт. Форма жөн гана тастыкталган маалыматтар менен mutation.mutate деп атайт.
Мунун эч кимиси туура эмес. Бул дагы эле идиоматикалык React болуп саналат жана RHF изоляциясын кайра көрсөтүүнүн аркасында компонент абдан натыйжалуу. Бирок, эгер сиз муну жазбаган адамга тапшырып, карап чыгуу баракчасы кандай шарттарда пайда болоорун түшүндүрүүнү сурансаңыз, алар showSubmit, 3-кадам көрсөтүү шарты жана навигация баскычынын логикасы аркылуу - үч өзүнчө жер - бир сапта айтыла турган эрежени калыбына келтириши керек. Форма иштейт, ооба, бирок жүрүм-турум чындыгында система катары текшерилбейт. Аны психикалык жактан ишке ашыруу керек. Андан да маанилүүсү, аны өзгөртүү инженердик тартууну талап кылат. Карап чыгуу кадамы качан көрсөтүлсө тууралоо сыяктуу кичинекей чыңдоо да компонентти түзөтүүнү, валидацияны жаңыртууну, тартуу өтүнүчүн ачууну, карап чыгууну күтүүнү жана кайра жайылтууну билдирет. 2-бөлүк: Схемага негизделген (SurveyJS) Эми схеманы колдонуп, ошол эле агымды түзөлү. Орнотуу npm Survey-core Survey-react-ui @tanstack/react-query орнотуу
Survey-coreThe MIT лицензиясы бар платформадан көз карандысыз иштөө убактысынын кыймылдаткычы SurveyJS'тин форманы көрсөтүүсүн камсыздайт - бул биз үчүн маанилүү бөлүгү. Ал JSON схемасын алат, андан ички моделди түзөт жана React компонентиңизде башка учурларда жашай турган нерселердин бардыгын иштетет: көрүнүү туюнтмаларын баалоо, алынган баалуулуктарды эсептөө, барактын абалын башкаруу, валидацияга көз салуу жана "толук" деген эмнени билдирерин чечүү. survey-react-uiБул моделди React менен байланыштырган UI / көрсөтүү катмары. Бул негизинен кыймылдаткычтын абалы өзгөргөн сайын кайра көрсөтүлүүчү <Суроо модели={model} /> компоненти. SurveyJS UI китепканалары Angular, Vue3 жана башка көптөгөн алкактар үчүн да жеткиликтүү.
Биргелешип, алар сизге башкаруу агымынын бир сызыгын жазбастан толук функционалдык, көп барактуу форманын иштөө убактысын беришет. Схема форматынын өзү, мурда айтылгандай, жөн гана JSON - DSL же менчик эч нерсе жок. Сиз аны сапка киргизип, файлдан импорттоп, APIден алып же маалымат базасынын тилкесинде сактап, иштөө учурунда гидраттай аласыз. Ошол эле форма, маалыматтар Мына ошол эле форма, бул жолу JSON объектиси катары көрсөтүлгөн. Схема бардыгын аныктайт: структура, валидация, көрүнүү эрежелери, алынган эсептөөлөр, барактарды навигациялоо — жана аны иштөө учурунда баалаган Моделге тапшырат. Бул толугу менен кандай көрүнөт:
экспорт const surveySchema = { аталышы: "Заказдын агымы", showProgressBar: "жогорку", беттер: [ {аты: "деталдары", элементтери: [ { түрү: "текст", аты: "firstName", isRequired: чыныгы }, { түрү: "текст", аты: "email", inputType: "email", isRequired "email", inputType: "türü: чыныгы", [{ электрондук почта" }] } ] }, { аты: "тартип", элементтер: [ { түрү: "текст", аты: "баасы", inputType: "сан", defaultValue: 0 }, { түрү: "текст", аты: "саны", inputType: "сан", defaultValue: 1 }, { түрү: "ашылуучу",аты: "taxRate", defaultValue: 0,1, тандоолор: [ { мааниси: 0,05, текст: "5%" }, { мааниси: 0,1, текст: "10%" }, { мааниси: 0,15, текст: "15%" } ] }, { түрү: "туюндурма", аты: "{анттык баа:" {}түрү:" "экспрессия", аты: "салык", туюнтма: "{субтотал} {taxRate}" }, { түрү: "туюндурма", аты: "бардыгы", туюнтма: "{кошумча жалпы} + {салык}" } ] }, {аты: "эсеп", элементтер: [ {түрү: "радиотоп", аты: "hasAccount", ["] ":түрү", тандоолор ":" {t. аты: "колдонуучунун аты", visibleIf: "{hasAccount} = "Ооба"", талап кылынат: чын символдор" }] }, { түрү: "рейтинг", аты: "канааттануу", rateMin: 1, rateMax: 5 }, { түрү: "комментарий", аты: "позитивдүү пикир", visibleIf: "{канааттануу} >= 4" }, { түрү: "комментарий", аты: "improvementFeedf:" <{visibleIf:} ] }, { name: "review", visibleIf: "{total} >= 100", элементтер: [] } ]};
Бир азга муну RHF версиясы менен салыштырыңыз.
Шарттуу түрдө талап кылынган логин жана сырсөз superRefine блогу жок. visibleIf: "{hasAccount} = 'Ооба'" isRequired: true менен айкалышып, эки маселени тең талаанын өзүндө, сиз таба турган жерден бирге иштетет. Аралык сумманы, салыкты жана жалпыны эсептеген useWatch + useMemo чынжырчасы бири-бирине аты менен шилтеме берген үч туюнтма талаасы менен алмаштырылат. RHF версиясында showSubmit аркылуу издөө аркылуу гана реконструкцияланган карап чыгуу бетинин шарты, 3-кадам көрсөтүү бутагы. Акырында, navigasyon баскычынын логикасы бет объектисинде бир visibleIf касиети болуп саналат.
Ошол эле логика бар. Болгону, схема ага компонентке жайылбастан, өзүнчө көрүнгөн жерде жашай турган жерди берет. Ошондой эле, схеманын түрүн колдоноорун эске алыңыз: кошумча сумма, салык жана жалпы үчүн ' туюнтма . туюнтма окуу үчүн гана жана негизинен эсептелген маанилерди көрсөтүү үчүн колдонулат. SurveyJS ошондой эле статикалык мазмун үчүн "html" түрүн колдойт, бирок эсептелген маанилер үчүн туюнтма туура тандоо. Эми реакция тарапка. Көрсөтүү жана тапшыруу Абдан жөнөкөй. Wire onComplete сиздин API'ге дал ушундай жол менен — useMutation же жөнөкөй алып келүү аркылуу:
import { useState, useEffect, useRef } "react";import { useMutation} from "@tanstack/react-query";import { Model} from "survey-core";import { Survey} from "survey-react-ui";импорт "survey-core/survey-core.css";
SurveyForm() экспорт функциясы {const [model] = useState(() => new Model(surveySchema));
const мутация = useMutation({ mutationFn: асинхрондук (маалымат) => { const res = күтүү алып келүү("/api/orders", { ыкма: "POST", аталыштар: { "Content-Type": "application/json" }, дене: JSON.stringify(маалымат), }); if (!res.ok) throw new Error("Failed to submit"); return res.json(); }, });
const mutationRef = useRef(мутация); mutationRef.current = мутация; useEffect(() => { const иштеткич = (жөнөтүүчү) => mutationRef.current.mutate(sender.data); model.onComplete.add(иштегич); return () => model.onComplete.remove(иштегич);}, [модель]); // ref ар бир рендердик иштеткичти кайра каттоодон сактайт (мутация объектинин идентификациясы өзгөрөт)
кайтуу (
<>
Pen SurveyJS-03-SurveyJS [Forked] менен sixthextinction караңыз.
onComplete колдонуучу акыркы көрүнгөн барактын аягына жеткенде күйөт. Ошентип, эгерде жалпы сан эч качан 100дөн ашпаса жана карап чыгуу барагы өткөрүп жиберилсе, анда ал дагы эле туура күйөт, анткени SurveyJS "акыркы бет" деген эмнени билдирерин чечүүдөн мурун көрүнүштү баалайт. Андан кийин, sender.data биринчи класстагы талаалар катары эсептелген маанилер менен бирге бардык жоопторду камтыйт (жалпы сумма, салык, жалпы), андыктан API жүгү onSubmitте кол менен чогултулган RHF версиясына окшош. ThemutationRef үлгүсү сиз каалаган жерге жете тургандай эле, сизге ар бир рендерде өзгөрүүчү мааниге туруктуу окуяны иштеткич керек - бул жөнүндө SurveyJS үчүн эч нерсе жок.
React компоненти мындан ары эч кандай бизнес логикасын камтыбайт. UseWatch, шарттуу JSX, кадам эсептегич, useMemo тизмеги, superRefine жок. React чындыгында жакшы болгон нерсени жасап жатат: компонентти көрсөтүү жана аны API чалууга өткөрүү. Реакциядан эмне чыкты?
тынчсыздануу RHF стек SurveyJS Көрүнүү JSX филиалдары visibleIf Туунду баалуулуктар useWatch / useMemo билдирүү Кайчылаш талаа эрежелери superFine Схема шарттары Навигация кадам абалы Page visibleIf Эреженин жайгашкан жери Файлдар боюнча бөлүштүрүлгөн Схемада борборлоштурулган
React'те калган нерсе - бул макет, стилдөө, тапшыруу өткөргүчтөрү жана колдонмо интеграциясы, башкача айтканда, React иш жүзүндө иштелип чыккан нерселер. Калганынын баары схемага жылдырылды жана схема жөн гана JSON объектиси болгондуктан, ал маалымат базасында сакталып, колдонмоңуздун кодунан көз карандысыз түрдө версиясы же жайылтууну талап кылбастан ички шаймандар аркылуу түзөтүлүшү мүмкүн. Карап чыгуу барагын козгогон босогону өзгөртүү керек болгон продукт менеджери муну компонентке тийбестен жасай алат. Бул формадагы жүрүм-туруму тез-тез өзгөрүп турган жана дайыма эле инженерлер тарабынан башкарылбаган командалар үчүн маанилүү операциялык айырма. Ар бир ыкманы качан колдонуу керек? Бул жерде мен үчүн иштеген жакшы эреже: форманы толугу менен жок кылууну элестетиңиз. Эмне жоготмок элеңиз?
Эгер бул экрандар болсо, сиз компоненттерге негизделген формаларды каалайсыз. Эгерде бул бизнес логикасы болсо, мисалы, босоголор, тармактык эрежелер жана реалдуу чечимдерди коддогон шарттуу талаптар, сиз схема кыймылдаткычын каалайсыз.
Ошо сыяктуу эле, эгер сиздин жолуңузга келе турган өзгөрүүлөр көбүнчө этикеткаларга, талааларга жана макетке байланыштуу болсо, RHF сизге жакшы кызмат кылат. Эгер алар шейшемби күнү түштөн кийин сиздин операцияңыз же юридикалык командаңыз билет тапшырбастан тууралашы керек болгон шарттар, натыйжалар жана эрежелер жөнүндө болсо, SurveyJS менен схема модели чынчыл болуп саналат. Бул эки ыкма чындыгында бири-бири менен атаандашпайт. Алар көйгөйлөрдүн ар кандай класстарын карашат жана качууга арзырлык ката - абстракциянын логиканын салмагына туура келбегендик - эреже системасын компонент катары кароо, анткени бул тааныш курал, же саясат кыймылдаткычына жетүү, анткени форма үч кадамга өсүп, шарттуу талаага ээ болду. Бул жерде биз курган форма чек аранын жанында атайылап отурат, айырманы ачып бере тургандай татаал, бирок салыштыруу бурмалангандай сезилет. Сиздин коддук базаңызда ыңгайсыз болуп калган реалдуу формалардын көбү, балким, ошол эле чекке жакын жерде отурат жана суроо, адатта, кимдир бирөө алардын чындыгында эмне экенин атадыбы деген суроо туулат. React Hook Form + Zodду төмөнкү учурларда колдонуңуз:
Формалар CRUD-багытталган; Логика тайыз жана UI башкарган; Инженерлер бардык жүрүм-турумуна ээ; Backend чындыктын булагы бойдон калууда.
SurveyJSти төмөнкү учурларда колдонуңуз:
Формалар бизнес чечимдерин коддойт; Эрежелер UIден көз карандысыз өнүгөт; Логика көрүнөө, текшерилүүчү же версияда болушу керек; Инженер эместер жүрүм-турумуна таасир этет; Бир эле форма бир нече фронтондо иштеши керек.