Овај чланак спонзорише СурвеиЈС Постоји ментални модел који већина Реацт програмера дели, а да о томе никада не разговарају наглас. Те форме увек треба да буду компоненте. То значи стек као што је:

Реацт Хоок Форм за локално стање (минимални поновни прикази, регистрација ергономског поља, императивна интеракција). Зод за валидацију (исправност уноса, валидација граница, рашчлањивање безбедан тип). Реацт Куери за позадину: подношење, поновни покушаји, кеширање, синхронизација сервера и тако даље.

А за огромну већину образаца - ваше екране за пријаву, ваше странице са подешавањима, ваше ЦРУД модале - ово функционише заиста добро. Сваки комад ради свој посао, компонује чисто, и можете прећи на делове ваше апликације који заправо разликују ваш производ. Али с времена на време, образац почиње да акумулира ствари као што су правила видљивости која зависе од ранијих одговора или изведене вредности које каскадирају кроз три поља. Можда чак и читаве странице које би требало прескочити или приказати на основу текућег зброја. Са првим условом рукујете помоћу усеВатцх-а и инлине гране, што је у реду. Онда још један. Затим посежете за суперРефине-ом да кодира правила унакрсних поља која ваша Зод шема не може да изрази на нормалан начин. Затим, навигација корака почиње да цури пословну логику. У неком тренутку, погледате шта сте направили и схватите да образац више није заправо кориснички интерфејс. То је више процес одлучивања, а стабло компоненти је управо тамо где сте га похранили. Овде мислим да се ментални модел за форме у Реацт-у ломи, и заиста нико није крив. РХФ + Зод стацк је одличан у ономе за шта је дизајниран. Проблем је у томе што смо склони да га наставимо да га користимо након тачке у којој се њене апстракције подударају са проблемом јер алтернатива захтева потпуно другачији начин размишљања о облицима. Овај чланак је о тој алтернативи. Да бисмо то показали, двапут ћемо направити потпуно исти образац у више корака:

Са Реацт Хоок Форм + Зод повезаним са Реацт Куери-ом за подношење, Са СурвеиЈС, који третира образац као податке — једноставну ЈСОН шему — а не као стабло компоненти.

Исти захтеви, иста условна логика, исти АПИ позив на крају. Затим ћемо тачно мапирати шта се померило, а шта је остало, и изложити практичан начин да одлучите који модел треба да користите и када. Форма коју правимо:

Овај образац ће користити ток у 4 корака: Корак 1: Детаљи

Име (обавезно), Е-пошта (обавезно, важећи формат).

Корак 2: Наручите

Јединична цена, количина, пореска стопа, Изведено: међузбир, порез, Укупно.

Корак 3: Рачун и повратне информације

Да ли имате налог? (да/не) Ако је Да → корисничко име + лозинка, оба су обавезна. Ако Не → е-пошта је већ прикупљена у кораку 1.

Оцена задовољства (1–5) Ако ≥ 4 → питајте „Шта вам се допало?“ Ако је ≤ 2 → питајте „Шта можемо да побољшамо?“

Корак 4: Прегледајте

Појављује се само ако је укупно >= 100 Коначна предаја.

Ово није екстремно. Али довољно је да се разоткрију архитектонске разлике. Део 1: Компонента вођена (Реацт Хоок Форм + Зод) Инсталација нпм инсталл реацт-хоок-форм зод @хоокформ/ресолверс @танстацк/реацт-куери

Зод Сцхема Почнимо са Зод шемом, јер се ту обично успоставља облик форме. За прва два корака — личне податке и унос поруџбине — све је једноставно: потребни низови, бројеви са минимумом и енум. Занимљиви део почиње када покушате да изразите условна правила.

импорт { з } из "зод";

екпорт цонст формСцхема = з.објецт({ фирстНаме: з.стринг().мин(1, "Обавезно"), емаил: з.стринг().емаил("Инвалид емаил"), цена: з.нумбер().мин(0), количина: з.нумбер().мин(1), такРате: з.нумбер(), хасАццоунт: з. з.стринг().оптионал(), лозинка: з.стринг().оптионал(), задовољство: з.нумбер().мин(1).мак(5), позитиванФеедбацк: з.стринг().оптионал(), побољшанаФеедбацк: з.стринг().оптионал(),}).суперРефине((дата, цткта) => {Ац "ес" => {Ац " (!дата.усернаме) { цтк.аддИссуе({ цоде: "цустом", патх: ["усернаме"], мессаге: "рекуиред" } } иф (!дата.пассворд || дата.пассворд.ленгтх < 6) { цтк.аддИссуе({ цоде: "пассворд") []); }

иф (дата.сатисфацтион >= 4 && !дата.поситивеФеедбацк) { цтк.аддИссуе({ цоде: "цустом", патх: ["поситивеФеедбацк"], порука: "Молимо вас да поделите шта вам се допало" }); }

иф (дата.сатисфацтион <= 2 && !дата.импровементФеедбацк) { цтк.аддИссуе({ цоде: "цустом", патх:["импровементФеедбацк"], порука: "Молим вас, реците нам шта да побољшамо" }); }});

тип извоза ФормДата = з.инфер<типеоф формСцхема>;

Обратите пажњу да се корисничко име и лозинка уписују као опциони() иако су условно обавезни јер Зодова шема на нивоу типа описује облик објекта, а не правила која регулишу када су поља важна. Условни захтев мора да живи унутар суперРефине, који се покреће након што је облик валидиран и има приступ целом објекту. То раздвајање није мана; то је управо оно за шта је алат дизајниран: суперРефине је место где иде логика унакрсних поља када се не може изразити у самој структури шеме. Оно што је такође приметно овде је оно што ова шема не изражава. Нема концепт страница, нема концепта која поља су видљива у којој тачки, нити концепт навигације. Све ће то живети негде другде. Компонента обрасца

импорт { усеФорм, усеВатцх } из "реацт-хоок-форм";импорт { зодРесолвер } из "@хоокформ/ресолверс/зод";импорт { усеМутатион } из "@танстацк/реацт-куери";импорт { усеСтате, усеМемо } из "реацт";импорт { формСцхема; импорт { формСцхема;

цонст СТЕПС = ["детаљи", "поруџбина", "налог", "преглед"];

типе ОрдерПаилоад = ФормДата & { међузбир: број; порез: број; укупно: број };

екпорт фунцтион РХФМултиСтепФорм() { цонст [корак, сетСтеп] = усеСтате(0);

цонст мутатион = усеМутатион({ мутатионФн: асинц (корисно оптерећење: ОрдерПаилоад) => { цонст рес = аваит фетцх("/апи/ордерс", { метод: "ПОСТ", заглавља: { "Цонтент-Типе": "апплицатион/јсон" }, тело: ЈСОН.стрингифи(корисно оптерећење), }); иф (!рес.ок) тхров нев Еррор("Фаилед то субмит"); ретурн рес.јсон(); }, });

цонст { регистер, цонтрол, хандлеСубмит, формСтате: { еррорс }, } = усеФорм<ФормДата>({ ресолвер: зодРесолвер(формСцхема), дефаултВалуес: { цена: 0, количина: 1, стопа пореза: 0,1, задовољство: 3, хасАццоунт: "Не", ); цонст цена = усеВатцх({ цонтрол, наме: "прице" }); цонст куантити = усеВатцх({ цонтрол, наме: "куантити" }); цонст такРате = усеВатцх({ цонтрол, наме: "такРате" }); цонст хасАццоунт = усеВатцх({ контрола, име: "хасАццоунт" }); цонст сатисфацтион = усеВатцх({ цонтрол, наме: "сатисфацтион" }); цонст субтотал = усеМемо(() => (цена ?? 0) * (количина ?? 1), [цена, количина]); цонст порез = усеМемо(() => међузбир * (такРате ?? 0), [субтотал, такРате]); цонст тотал = усеМемо(() => међузбир + порез, [субтотал, порез]); цонст онСубмит = (подаци: ФормДата) => мутатион.мутате({ ...подаци, међузбир, порез, укупно }); цонст сховСубмит = (корак === 2 && укупно < 100) || (корак === 3 && укупно >= 100)

ретурн ( <форм онСубмит={хандлеСубмит(онСубмит)}> {степ === 0 && ( <> <инпут {...регистер("фирстНаме")} плацехолдер="Фирст Наме" /> <инпут {...регистер("емаил")} плацехолдер="Емаил" /> )}

{степ === 1 && ( <> <инпут типе="нумбер" {...регистер("прице", { валуеАсНумбер: труе })} /> <инпут типе="нумбер" {...регистер("куантити", { валуеАсНумбер: труе })} /> <селецт {...регистер("такРате)" {:такРате} валуе="0.05">5% <оптион валуе="0.1">10% <оптион валуе="0.15">15%

<див>Субтотал: {субтотал} <див>Порез: {так} <див>Укупно: {тотал} )}

{степ === 2 && ( <> <селецт {...регистер("хасАццоунт")}> <оптион валуе="Иес">Да <оптион валуе="Не">Не

{хасАццоунт === "Да" && ( <> <инпут {...регистер("усернаме")} плацехолдер="Корисничко име" /> <инпут {...регистер("пассворд")} плацехолдер="Лозинка" /> )}

<инпут типе="нумбер" {...регистер("сатисфацтион", { валуеАсНумбер: труе })} />

{сатисфацтион >= 4 && ( <тектареа {...регистер("поситивеФеедбацк")} /> )}

{сатисфацтион <= 2 && ( <тектареа {...регистер("импровементФеедбацк")}/> )} )}

{степ === 3 && укупно >= 100 && <див>Прегледајте и пошаљите}

<див> {степ > 0 && <буттон типе="буттон" онЦлицк={() => сетСтеп(степ - 1)}>Назад} {сховСубмит ? ( <буттон типе="субмит" дисаблед={мутатион.исПендинг}> {мутатион.исПендинг ? "Субмиттинг..." : "Субмит"} ) : корак < СТЕПС.ленгтх - 1 ? ( <буттон типе="буттон" онЦлицк={() => сетСтеп(степ + 1)}>Следеће ) : нулл} {мутатион.исЕррор && <див>Грешка: {мутатион.еррор.мессаге}} );}

Погледајте Пен СурвеиЈС-03-РХФ [форкед] би сиктхектинцтион. Овде се доста тога дешава и вреди успорити да бисте приметили где су ствари завршиле.

Изведене вредности — међузбир, порез, укупно — се израчунавају у компоненти преко усеВатцх и усеМемо јер зависе од вредности поља уживо и за њих не постоји друго природно место. Правила видљивости за корисничко име, лозинку, позитивне повратне информације и повратне информације побољшања живе у ЈСКС-у као уметнути услови. Логика прескакања корака — страница за преглед која се појављује само када је укупно >= 100 — је уграђена у променљиву сховСубмит и услов за рендеровање у кораку 3. Сама навигација је само усеСтате бројач који ручно повећавамо. Реацт Куери управља поновним покушајима, кеширањем и поништавањем. Образац само позива мутатион.мутате са потврђеним подацима.

Ништа од овога није погрешно, само по себи. Ово је још увек идиоматски Реацт, а компонента је прилично ефикасна захваљујући томе како РХФ изолује ре-рендере. Али ако бисте ово предали некоме ко то није написао и замолили га да објасне под којим условима се страница за преглед појављује, они би морали да прођу кроз сховСубмит, услов 3. корака рендеровања и логику навигационог дугмета — три одвојена места — да би реконструисали правило које је могло бити наведено у једном реду. Образац функционише, да, али понашање није стварно проверљиво као систем. Мора да се изврши ментално. Што је још важније, промена захтева ангажовање инжењера. Чак и мала подешавања, попут прилагођавања када се прикаже корак прегледа, значи уређивање компоненте, ажурирање валидације, отварање захтева за повлачење, чекање на преглед и поновно постављање. 2. део: вођен шемом (СурвеиЈС) Сада направимо исти ток користећи шему. Инсталација нпм инсталл сурвеи-цоре сурвеи-реацт-уи @танстацк/реацт-куери

СурвеиЈС-ов језгро: платформски независан механизам за извршавање са лиценцом МИТ-а који покреће СурвеиЈС-ов приказ форме – део до којег нам је овде стало. Узима ЈСОН шему, из ње гради интерни модел и обрађује све што би иначе живело у вашој Реацт компоненти: процену израза видљивости, израчунавање изведених вредности, управљање стањем странице, праћење валидације и одлучивање шта значи „потпуно“ с обзиром на то које су странице заиста приказане. сурвеи-реацт-уи УИ / слој за рендеровање који повезује тај модел са Реацт-ом. То је у суштини компонента <Сурвеи модел={модел} /> која се поново приказује кад год се промени стање машине. СурвеиЈС УИ библиотеке су такође доступне за Ангулар, Вуе3 и многе друге оквире.

Заједно, они вам дају потпуно функционално време за извршавање обрасца са више страница без писања једне линије тока контроле. Сам формат шеме је, као што је већ речено, само ЈСОН — без ДСЛ-а или било чега власничког. Можете да га уградите, увезете из датотеке, преузмете из АПИ-ја или га ускладиштите у колони базе података и хидратизујете у току извршавања. Исти облик, као подаци Ево истог облика, овог пута израженог као ЈСОН објекат. Шема дефинише све: структуру, валидацију, правила видљивости, изведене калкулације, навигацију по страници — и предаје је моделу који то процењује током извршавања. Ево како то изгледа у целости:

екпорт цонст сурвеиСцхема = { титле: "Ток поруџбине", сховПрогрессБар: "топ", пагес: [ { наме: "детаилс", елементс: [ { типе: "тект", наме: "фирстНаме", исРекуиред: труе }, { типе: "тект", наме: "емаил", инпутТипе: "емаил", исРекуиред:{ тект: валидаторс:{ тект: валидаторс:{ тект: валидаторс" }] } ] }, { наме: "поруџбина", елементи: [ { тип: "текст", назив: "цена", инпутТипе: "број", дефаултВалуе: 0 }, { тип: "текст", назив: "количина", инпутТипе: "број", дефаултВалуе: 1 }, { тип: "падајући",име: "такРате", дефаултВалуе: 0.1, избори: [ { валуе: 0.05, тект: "5%" }, { валуе: 0.1, тект: "10%" }, { валуе: 0.15, тект: "15%" } ] }, { типе: "екпрессион", наме: {типе: "субтотал" {} израз:} "субтотал", {} "екпрессион", наме: "так", израз: "{субтотал} {такРате}" }, { типе: "екпрессион", наме: "тотал", екпрессион: "{субтотал} + {так}" } } }, { наме: "аццоунт", елементс: [ { типе: "радиогроуп", наме: "хасАццоунтес", избори ", {тект:"] "усернаме", висиблеИф: "{хасАццоунт} = 'Да'", исРекуиред: труе }, { типе: "тект", наме: "пассворд", инпутТипе: "пассворд", висиблеИф: "{хасАццоунт} = 'Иес'", исРекуиред: труе, валидатори знакова: [{ типе: "тект:ин6", мин.} }, { типе: "ратинг", наме: "сатисфацтион", ратеМин: 1, ратеМак: 5 }, { типе: "цоммент", наме: "поситивеФеедбацк", висиблеИф: "{сатисфацтион} >= 4" }, { типе: "цоммент", наме: "импровементФеедбацк", {= висиблеИффацтион: {= висиблеИф: } "ревиев", висиблеИф: "{тотал} >= 100", елементи: [] } ]};

Упоредите ово са РХФ верзијом на тренутак.

Блок суперРефине који је условно захтевао корисничко име и лозинку је нестао. висиблеИф: "{хасАццоунт} = 'Иес'" у комбинацији са исРекуиред: труе решава оба проблема заједно, на самом пољу, где бисте очекивали да ћете их пронаћи. Ланац усеВатцх + усеМемо који је израчунао међузбир, порез и збир замењен је са три поља израза која се међусобно позивају по имену. Стање странице за преглед, које је у РХФ верзији било реконструисано само праћењем кроз сховСубмит, грану рендеровања у кораку 3. И коначно, логика навигационог дугмета је једно својство висиблеИф на објекту странице.

Ту је иста логика. Само што му шема даје место да живи тамо где је видљива изоловано, уместо да се шири по компоненти. Такође, имајте на уму да шема користи тип: 'израз' за међузбир, порез и тотал. Израз је само за читање и користи се углавном за приказ израчунатих вредности. СурвеиЈС такође подржава тип: 'хтмл' за статички садржај, али за израчунате вредности израз је прави избор. Сада за Реацт страну. Рендеринг Анд Субмиссион Врло једноставно. Повежите онЦомплете са својим АПИ-јем на исти начин — преко усеМутатион или обичног преузимања:

импорт { усеСтате, усеЕффецт, усеРеф } из "реацт";импорт { усеМутатион } из "@танстацк/реацт-куери";импорт { Модел } из "сурвеи-цоре";импорт { Сурвеи } из "сурвеи-реацт-уи";импорт "сурвеи-цоре/сурвеи-цоре.

екпорт фунцтион СурвеиФорм() { цонст [модел] = усеСтате(() => нев Модел(сурвеиСцхема));

цонст мутатион = усеМутатион({ мутатионФн: асинц (подаци) => { цонст рес = аваит фетцх("/апи/ордерс", { метод: "ПОСТ", заглавља: { "Цонтент-Типе": "апплицатион/јсон" }, тело: ЈСОН.стрингифи(подаци), }); иф (!рес.ок) тхров нев Еррор("Фаилед то субмит"); ретурн рес.јсон(); }, });

цонст мутатионРеф = усеРеф(мутација); мутатионРеф.цуррент = мутација; усеЕффецт(() => { цонст хандлер = (сендер) => мутатионРеф.цуррент.мутате(сендер.дата); модел.онЦомплете.адд(хандлер); ретурн () => модел.онЦомплете.ремове(хандлер); }, [модел]); // реф избегава поновно регистровање руковаоца при сваком приказивању (промене идентитета објекта мутације)

повратак ( <> <Сурвеи модел={модел} /> {мутатион.исЕррор && <див>Грешка: {мутатион.еррор.мессаге}} ); }

Погледајте Пен СурвеиЈС-03-СурвеиЈС [форкед] би сиктхектинцтион.

онЦомплете се покреће када корисник дође до краја последње видљиве странице. Дакле, ако укупан број никада не пређе 100 и страница за преглед је прескочена, она се и даље исправно покреће јер СурвеиЈС процењује видљивост пре него што одлучи шта значи „последња страница“. Затим, сендер.дата садржи све одговоре заједно са израчунатим вредностима (субтотал, так, тотал) као првокласна поља, тако да је корисно оптерећење АПИ-ја идентично ономе што је РХФ верзија саставила ручно у онСубмит. ТхемутатионРеф образац је исти за којим бисте посегнули свуда где вам је потребан стабилан руковалац догађаја преко вредности која се мења при сваком рендеру - ништа у вези са СурвеиЈС-ом.

Реацт компонента више уопште не садржи никакву пословну логику. Нема усеВатцх-а, нема условног ЈСКС-а, нема бројача корака, нема усеМемо ланца, нема суперРефине. Реацт ради оно у чему је заправо добар: рендерује компоненту и повезује је са АПИ позивом. Шта је изашло из реакције?

Забринутост РХФ Стацк СурвеиЈС Видљивост ЈСКС гране висиблеИф Изведене вредности усеВатцх / усеМемо израз Правила унакрсних поља суперРефине Услови шеме Навигација корак стање Паге висиблеИф Локација правила Дистрибуирано по датотекама Централизовано у шеми

Оно што остаје у Реацт-у је изглед, стил, ожичење подношења и интеграција апликација, што ће рећи, ствари за које је Реацт заправо дизајниран. Све остало је премештено у шему, а пошто је шема само ЈСОН објекат, може се складиштити у бази података, верзионисана независно од кода апликације или уређивана помоћу интерних алата без потребе за примену. Менаџер производа који треба да промени праг који покреће страницу за преглед може то да уради без додиривања компоненте. То је значајна оперативна разлика за тимове у којима се понашање форме често развија и није увек вођено инжењерима. Када користити сваки приступ? Ево доброг правила које ми функционише: замислите да у потпуности избришете образац. Шта бисте изгубили?

Ако су у питању екрани, желите обрасце вођене компонентама. Ако је то пословна логика, као што су прагови, правила гранања и условни захтеви који кодирају стварне одлуке, желите механизам шеме.

Слично томе, ако се промене које долазе углавном односе на ознаке, поља и распоред, РХФ ће вам добро послужити. Ако се ради о условима, исходима и правилима која ће ваши оперативни или правни тим можда морати да прилагоде у уторак поподне без подношења пријаве, модел шеме са СурвеиЈС је искренији. Ова два приступа заправо нису у конкуренцији један са другим. Они се баве различитим класама проблема, а грешка коју вреди избегавати је неусклађеност апстракције са тежином логике – третирање система правила као компоненте јер је то познато оруђе, или посезање за механизмом политике јер је образац нарастао на три корака и добио условно поље. Форма коју смо овде изградили намерно се налази близу границе, довољно сложена да разоткрије разлику, али не толико екстремна да се поређење чини намештеним. Већина стварних форми које су постале гломазне у вашој бази кода вероватно се налазе близу те исте границе, а питање је обично само да ли је неко именовао оно што заправо јесу. Користите Реацт Хоок Форм + Зод када:

Обрасци су ЦРУД оријентисани; Логика је плитка и вођена УИ; Инжењери поседују све понашање; Бацкенд остаје извор истине.

Користите СурвеиЈС када:

Обрасци кодирају пословне одлуке; Правила се развијају независно од корисничког интерфејса; Логика мора бити видљива, подложна ревизији или верзија; Неинжењери утичу на понашање; Исти образац мора да се налази на више фронтендова.

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free