React ve Next.js'de Dinamik Formlar Oluşturma Siber Güvenlik

React ve Next.js'de Dinamik Formlar Oluşturma

React ve Next.js'de Dinamik Formlar Oluşturma...

React ve Next.js'de Dinamik Formlar Oluşturma

Twitter'da paylaş, LinkedIn

Bazı formlar kullanıcı arayüzünde kalırken diğerleri sessizce kural motorlarına dönüşür. İşte bu iki farklı yaklaşımın var olmasının nedeni ve aralarında nasıl seçim yapılacağı. Bazı formlar kullanıcı arayüzünde kalırken diğerleri sessizce kural motorlarına dönüşür. İşte bu iki farklı yaklaşımın var olmasının nedeni ve aralarında nasıl seçim yapılacağı.

Çoğu React geliştiricisinin yüksek sesle tartışmadan paylaştığı zihinsel bir model var. Bu formların her zaman bileşenler olması gerekiyordu. Bu şuna benzer bir yığın anlamına gelir:

Yerel durum için React Hook Formu (minimum yeniden işleme, ergonomik alan kaydı, zorunlu etkileşim).

Sistem Güvenliği

yerel durum için (minimum yeniden oluşturma, ergonomik alan kaydı, zorunlu etkileşim). Doğrulama için Zod (giriş doğruluğu, sınır doğrulama, tür açısından güvenli ayrıştırma).

doğrulama için (giriş doğruluğu, sınır doğrulama, tür açısından güvenli ayrıştırma). Arka uç için React Query: gönderme, yeniden denemeler, önbelleğe alma, sunucu senkronizasyonu vb.

Önemli Gelişmeler

Ve formların büyük çoğunluğu için (giriş ekranlarınız, ayar sayfalarınız, CRUD modelleriniz) bu gerçekten işe yarıyor. Her parça işini yapar, temiz bir şekilde oluşur ve uygulamanızın ürününüzü gerçekten farklı kılan kısımlarına geçebilirsiniz.

Ancak arada bir, bir form daha önceki yanıtlara bağlı olan görünürlük kuralları veya üç alandan geçen türetilmiş değerler gibi şeyleri biriktirmeye başlar. Belki de toplam sayıya göre atlanması veya gösterilmesi gereken sayfaların tamamı bile olabilir.

Teknik Analiz

İlk koşulluyu bir useWatch ve satır içi dalla halledersiniz, bu da sorun değil. Sonra bir tane daha. Daha sonra Zod şemanızın normal şekilde ifade edemediği alanlar arası kuralları kodlamak için superRefine'a ulaşıyorsunuz. Ardından adım navigasyonu iş mantığını sızdırmaya başlar. Bir noktada, oluşturduğunuz şeye bakıyorsunuz ve formun artık gerçekten kullanıcı arayüzü olmadığını fark ediyorsunuz. Bu daha çok bir karar sürecidir ve bileşen ağacı tam da onu sakladığınız yerdir.

React'taki formlara ilişkin zihinsel modelin burada çöktüğünü düşünüyorum ve bu aslında kimsenin hatası değil. RHF + Zod yığını, tasarlandığı amaç açısından mükemmeldir. Sorun şu ki, soyutlamaları sorunla eşleşinceye kadar onu kullanmaya devam etme eğilimindeyiz çünkü alternatif, formlar hakkında tamamen farklı bir düşünme tarzı gerektiriyor.

Sonuç ve Değerlendirme

Bu makale bu alternatif hakkındadır. Bunu göstermek için aynı çok adımlı formu iki kez oluşturacağız:

React Hook Form + Zod, gönderim için React Query'ye bağlanırken, formu bir bileşen ağacı yerine veri olarak (basit bir JSON şeması) ele alan SurveyJS ile.

Uzmanların Görüşleri

Aynı gereksinimler, aynı koşullu mantık, sonunda aynı API çağrısı. Daha sonra tam olarak neyin taşındığını ve neyin kaldığını haritalandıracağız ve hangi modeli ne zaman kullanmanız gerektiğine karar vermenin pratik bir yolunu ortaya koyacağız.

Bu formda 4 adımlı bir akış kullanılacaktır:

E-posta (gerekli, geçerli format).

Detaylar ve Etkileri

Adım 2: Sipariş Verin

Türetilmiş: Ara Toplam, Vergi, Toplam.

3. Adım: Hesap ve Geri Bildirim

Nasıl Önlem Alınmalı?

Hesabınız var mı? (Evet/Hayır) Evet ise → kullanıcı adı + şifre, her ikisi de gereklidir. Hayır ise → e-posta zaten 1. adımda toplandı.

Memnuniyet derecesi (1–5) ≥ 4 ise → “Neyi beğendiniz?” diye sorun. ≤ 2 ise → “Neyi geliştirebiliriz?” diye sorun.

Yalnızca toplam >= 100 ise görünür

Bu aşırı değil. Ancak mimari farklılıkları ortaya çıkarmak yeterlidir.

Gelecekte Ne Bekleniyor?

Bölüm 1: Bileşen Odaklı (React Hook Formu + Zod)

npm react-hook-form zod'u kurun @hookform/resolvers @tanstack/react-query

Zod şemasıyla başlayalım çünkü genellikle formun şekli burada oluşturulur. İlk iki adımda (kişisel ayrıntılar ve sipariş girişleri) her şey basittir: gerekli dizeler, minimumlu sayılar ve bir numaralandırma. İşin ilginç kısmı koşullu kuralları ifade etmeye çalıştığınızda başlıyor.

{ z }'yi "zod"dan içe aktarın; const formSchema = z.object({ FirstName: z.string().min(1, "Gerekli"), email: z.string().email("Geçersiz e-posta"), fiyat: z.number().min(0), miktar: z.number().min(1), TaxRate: z.number(), hasAccount: z.enum(["Evet", "Hayır"]), kullanıcı adı: z.string().opsiyonel(), şifre: z.string().isteğe bağlı(), memnuniyet: z.number().min(1).max(5), pozitifFeedback: z.string().isteğe bağlı(), iyileştirmeFeedback: z.string().isteğe bağlı(), }).superRefine((data, ctx) => { if (data.hasAccount === "Evet") { if (!data.username) { ctx.addIssue({ code: "custom", path: ["kullanıcı adı"], mesaj: "Gerekli" }); if (!data.password || data.password.len) gth < 6) { ctx.addIssue({ code: "custom", path: ["password"], message: "Min 6 karakter" }); } } if (data.satisfaction >= 4 && !data.positiveFeedback) { ctx.addIssue({ code: "custom", path: ["positiveFeedback"], message: "Lütfen beğendiklerinizi paylaşın" }); } if (data.satisfaction <= 2 && !data.improvementFeedback) { ctx.addIssue({ code: "custom", path: ["improvementFeedback"], message: "Lütfen bize neyi geliştirmemiz gerektiğini söyleyin" }); } }); dışa aktarma türü FormData = z.infer;

Zod'un tür düzeyindeki şeması, alanların ne zaman önemli olduğunu belirleyen kuralları değil, nesnenin şeklini tanımladığından, koşullu olarak gerekli olmalarına rağmen kullanıcı adı ve parolanın isteğe bağlı() olarak yazıldığına dikkat edin.

Koşullu gereksinim, şekil doğrulandıktan sonra çalışan ve nesnenin tamamına erişebilen superRefine içinde bulunmalıdır. Bu ayrılık bir kusur değil; araç tam da bunun için tasarlandı: superRefine, şema yapısının kendisinde ifade edilemediğinde alanlar arası mantığın gittiği yerdir.

Burada dikkat çeken şey, bu şemanın neyi ifade etmediğidir. Sayfa kavramı, hangi alanların hangi noktada görülebileceği kavramı ve gezinme kavramı yoktur. Bunların hepsi başka bir yerde yaşayacak.

"react-hook-form"dan { useForm, useWatch }'ı içe aktarın; { zodResolver }'ı "@hookform/resolvers/zod" adresinden içe aktarın; { useMutation }'ı "@tanstack/react-query"den içe aktarın; { useState, useMemo }'yu "react"tan içe aktarın; { formSchema'yı içe aktarın, "./schema"dan FormData yazın; const ADIMLAR = ["ayrıntılar", "sipariş", "hesap", "inceleme"]; OrderPayload yazın = FormData & { subtotal: number; vergi: sayı; toplam: sayı }; dışa aktarma işlevi RHFMultiStepForm() { const [step, setStep] = useState(0); const mutasyon = useMutation({ mutasyonFn: async (payload: OrderPayload) => { const res = wait fetch("/api/orders", { method: "POST", başlıklar: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); if (!res.ok) throw new Error("Gönderme başarısız oldu"); return res.json(); }, }); const { kayıt, kontrol, tanıtıcıSubmit, formState: { hatalar }, } = useForm({ çözümleyici: zodResolver(formSchema), defaultValues: { fiyat: 0, miktar: 1, vergiRate: 0,1, memnuniyet: 3, hasAccount: "Hayır", }, }); const fiyat = useWatch({ kontrol, isim: "fiyat" }); const miktar = useWatch({ kontrol, isim: "miktar" }); const vergiRate = useWatch({ control, name: "taxRate" }); const hasAccount = useWatch({ control, name: "hasAccount" }); const memnuniyeti = useWatch({ kontrol, isim: "memnuniyet" }); const alt toplam = useMemo(() => (fiyat ?? 0) * (miktar ?? 1), [fiyat, miktar]); const vergi = useMemo(() => alt toplam * (vergiOranı ?? 0), [alttoplam, vergiOranı]); const toplam = useMemo(() => alt toplam + vergi, [alt toplam, vergi]); const onSubmit = (data: FormData) => mutasyon.mutate({ ...data, subtotal, vergi, total }); const showSubmit = (adım === 2 && toplam < 100) || (adım === 3 && toplam >= 100) return (

{step === 0 && ( <> )} {step === 1 && ( <>
Alttoplam: {subtotal
Vergi: {tax
Toplam: {toplam
)} {step === 2 && ( <> {hasAccount === "Evet" && ( <> )} {memnuniyet >= 4 && (