Takip et

NextJS ile Tek Form: Oluşturma ve Düzenleme Deneyimini Birleştirme

Modern web uygulamaları geliştirirken, kullanıcıların veri girişi yaptığı formlar merkezi bir rol oynar. Peki ya bir veriyi oluşturmak ve düzenlemek için ayrı ayrı formlar tasarlamak yerine, tüm bu süreçleri tek bir çatı altında birleştirebilir miyiz? Bu makalede, Next.js ekosistemi içinde React Hook Form ve Zod kütüphanelerini kullanarak, kod tekrarını en aza indiren, kullanıcı deneyimini iyileştiren ve geliştirme sürecini hızlandıran “tek form” yaklaşımını nasıl hayata geçirebileceğimizi adım adım inceleyeceğiz. Bu strateji, özellikle veri yoğun uygulamalarda büyük bir fark yaratabilir.

Web uygulamalarında genellikle bir “yeni kayıt oluştur” ve “mevcut kaydı düzenle” iş akışı bulunur. Örneğin, bir ürün yönetim panelinde yeni bir ürün eklerken farklı bir form, mevcut bir ürünün bilgilerini güncellerken ise neredeyse aynı alanlara sahip başka bir form kullanıldığına sıkça rastlanır. İlk bakışta bu durum mantıklı gibi görünse de, aslında beraberinde birçok zorluğu getirir. En belirgin sorunlardan biri kod tekrarıdır. Her iki form için de benzer veya aynı input alanlarını, doğrulama kurallarını ve gönderme mantığını ayrı ayrı yazmak, hem zaman kaybına neden olur hem de bakım maliyetlerini artırır.

Dahası, kod tekrarı beraberinde tutarsızlık riskini de getirir. Bir formdaki doğrulama kuralı güncellendiğinde, diğer formda da aynı değişikliği manuel olarak yapmak gerekir ki bu da insan hatasına açık bir süreçtir. Kullanıcı deneyimi açısından bakıldığında ise, iki farklı formun tasarımı veya davranışındaki küçük farklılıklar, kullanıcıda kafa karışıklığı yaratabilir ve uygulamanın genel kalitesini düşürebilir. Örneğin, bir formda alanlar belirli bir sıradayken, diğerinde farklı bir düzende olması veya hata mesajlarının farklı stillerde görüntülenmesi gibi durumlar, kullanıcının adapte olmakta zorlanmasına yol açabilir.

Özellikle büyük ve karmaşık uygulamalarda, bu tür ayrı ayrı formların yönetimi zamanla içinden çıkılmaz bir hal alabilir. Yeni bir özellik eklendiğinde veya mevcut bir alan güncellendiğinde, bu değişikliğin tüm ilgili formlara yansıtılması gerekir. Bu da geliştirme süreçlerini yavaşlatır ve hata potansiyelini artırır. İşte tam da bu noktada “birleşik oluşturma ve düzenleme formu” yaklaşımı devreye girer. Bu yaklaşım, temel olarak aynı verinin hem oluşturulması hem de düzenlenmesi için tek bir bileşen, tek bir doğrulama şeması ve tek bir gönderme mantığı kullanmayı hedefler. Next.js’in sağladığı güçlü yönlerle birleştiğinde, bu yaklaşım hem geliştiricilerin iş yükünü hafifletir hem de son kullanıcıya daha tutarlı ve akıcı bir deneyim sunar. Bu sayede, uygulamanın ölçeklenebilirliği artarken, bakım ve geliştirme süreçleri de önemli ölçüde basitleşir.

Next.js, React Hook Form ve Zod’a Hızlı Bir Bakış: Tek Formun Temel Taşları

Birleşik form stratejisini başarıyla uygulamak için doğru araç setini seçmek kritik öneme sahiptir. Bu makalede, Next.js’in sunduğu altyapıyı kullanarak, React Hook Form’u form yönetimi için, Zod’u ise şema tabanlı veri doğrulama için kullanacağız. Bu üçlünün birleşimi, bize güçlü, esnek ve performanslı bir form çözümü sunar.

Next.js’in Rolü Nedir?

Next.js, React tabanlı bir full-stack framework olup, sunucu tarafı renderlama (SSR), statik site üretimi (SSG) ve API rotaları (API Routes) gibi özellikleriyle modern web uygulamaları geliştirmek için ideal bir platformdur. Tek form yaklaşımında Next.js’in sunduğu avantajlar şunlardır:

  • Rotalama (Routing): Next.js’in dosya tabanlı rotalama sistemi, örneğin /urunler/yeni ve /urunler/[id]/duzenle gibi farklı URL’ler üzerinden tek bir form bileşenine erişim sağlamamızı kolaylaştırır.
  • API Rotaları: Sunucu tarafında veri kaydetme (POST) ve güncelleme (PUT) işlemleri için güvenli ve ölçeklenebilir API uç noktaları oluşturmamızı sağlar. Bu sayede, form verilerini doğrudan veritabanına gönderebiliriz.
  • Veri Ön Yükleme (Data Fetching): Düzenleme senaryolarında, mevcut verileri form alanlarına önceden yüklemek için getServerSideProps veya React Server Components gibi Next.js veri çekme yöntemlerini kullanabiliriz.
Uzman İpucu: Next.js’in App Router yapısıyla, Server Components kullanarak form verilerini sunucuda doğrudan çekebilir ve Client Component’e prop olarak ileterek daha az JavaScript gönderimi sağlayabilirsiniz.

React Hook Form Neden Form Yönetimi İçin İdeal?

React Hook Form, performans odaklı ve kullanımı kolay bir form yönetim kütüphanesidir. Geleneksel form kütüphanelerinin aksine, bileşenlerin yeniden render edilmesini minimuma indirerek performansı artırır. Temel avantajları şunlardır:

  • Performans: Kontrolsüz bileşenler (uncontrolled components) yaklaşımını benimseyerek, her input değişikliğinde tüm formun yeniden render edilmesini engeller. Bu, özellikle büyük formlarda hissedilir bir hız artışı sağlar.
  • Basitlik: Hook tabanlı API’si sayesinde form durumunu yönetmek oldukça kolaydır. useForm hook’u ile formun tüm kontrolünü ele alabilirsiniz.
  • Doğrulama Entegrasyonu: Zod, Yup, Joi gibi popüler doğrulama kütüphaneleriyle sorunsuz entegrasyon sunar.
  • Az Kod: Form state’ini manuel olarak yönetmek için az sayıda kod yazarsınız, bu da kod tekrarını azaltır.

import { useForm } from 'react-hook-form';

function MyForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  
  const onSubmit = data => console.log(data);

  return (
    
{errors.name && İsim gerekli}
); }

Yukarıdaki örnekte görüldüğü gibi, register fonksiyonu ile input alanlarını forma bağlamak oldukça pratiktir. Bu sayede, formun değerleri otomatik olarak yönetilir ve submit işlemi sırasında tüm veriler tek bir obje olarak elde edilir.

Zod ile Şema Tabanlı Doğrulamanın Gücü

Zod, TypeScript uyumlu, şema tabanlı bir doğrulama kütüphanesidir. Form verilerini hem istemci hem de sunucu tarafında aynı şema ile doğrulamak için mükemmel bir araçtır. Zod'un başlıca faydaları şunlardır:

  • Tip Güvenliği: Zod şemaları, verinin beklenen tipini ve yapısını tanımlar. Bu şemalar TypeScript tiplerine dönüştürülebildiği için, hem doğrulama hem de tip güvenliği aynı anda sağlanır.
  • Çapraz Ortam Doğrulama: Aynı Zod şemasını hem React Hook Form ile istemci tarafında hem de Next.js API rotalarında sunucu tarafında kullanarak kod tekrarını ortadan kaldırırız.
  • Okunabilirlik ve Esneklik: Şemalarınızı deklaratif bir şekilde tanımlayabilirsiniz. Zincirleme metotlarla karmaşık doğrulama kuralları oluşturmak çok kolaydır (örn. z.string().min(3).max(50).email()).

import { z } from 'zod';

const productSchema = z.object({
  name: z.string().min(3, "Ürün adı en az 3 karakter olmalı."),
  description: z.string().optional(),
  price: z.number().min(0.01, "Fiyat 0'dan büyük olmalı."),
  category: z.enum(["elektronik", "giyim", "ev"]),
});

type ProductFormData = z.infer;

Bu üç teknolojinin birleşimi, tek form yaklaşımını modern, tip güvenli ve performant bir şekilde uygulamak için güçlü bir temel oluşturur. Böylece, hem geliştirme verimliliğini artırabilir hem de son kullanıcılara sorunsuz bir deneyim sunabiliriz.

Vaka Analizi: Ürün Yönetimi Paneli - Tek Bir Form ile Ürün Oluşturma ve Düzenleme Nasıl Yapılır?

Haydi, teoriden pratiğe geçelim ve gerçek bir dünya senaryosu üzerinden tek form yaklaşımını inceleyelim: Bir e-ticaret uygulamasının yönetim paneli için ürün oluşturma ve düzenleme işlevselliği. Bu senaryoda, yöneticiler hem yeni ürünler ekleyebilecek hem de mevcut ürünlerin detaylarını güncelleyebilecekler.

Mevcut durumda, geleneksel yaklaşımla genellikle iki ayrı sayfa ve iki ayrı form bulunur:

  1. /admin/products/new: Yeni bir ürün oluşturmak için boş bir form.
  2. /admin/products/[id]/edit: Belirli bir id'ye sahip ürünün bilgilerini düzenlemek için, mevcut verilerle önceden doldurulmuş bir form.

Bu vaka analizinde amacımız, bu iki sayfayı tek bir bileşen ve tek bir form çatısı altında birleştirmektir. Bunun için aşağıdaki temel mimariyi izleyeceğiz:

  • Client Side (Next.js Sayfaları ve Form Bileşeni): Kullanıcı arayüzünü (formu) render edecek, React Hook Form ile form durumunu yönetecek ve Zod ile istemci tarafı doğrulamayı gerçekleştirecek. Form gönderildiğinde, Next.js API rotalarına bir istek gönderecek.
  • Server Side (Next.js API Rotaları): Formdan gelen verileri alacak, Zod ile sunucu tarafı doğrulamayı tekrar edecek, veritabanına kaydetme (oluşturma) veya güncelleme işlemlerini yapacak ve istemciye bir yanıt döndürecek.

Bir ürünün temel veritabanı yapısı basitçe şu alanları içerebilir:

Alan Adı Veri Tipi Açıklama Zorunlu Mu?
id String (UUID) Ürünün benzersiz kimliği Evet (Sistem tarafından atanır)
name String Ürünün adı Evet
description String Ürünün detaylı açıklaması Hayır
price Number Ürünün fiyatı Evet
category String Ürünün kategorisi (örn. "elektronik", "giyim") Evet
stock Number Mevcut stok adedi Evet

Bu yapıyı göz önünde bulundurarak, hem yeni bir ürün eklerken hem de mevcut bir ürünü güncellerken bu alanların formda yer alması gerekecektir. İşte tam da bu noktada, tek form bileşenimizin esnekliği ve adaptasyonu önem kazanır. Form, bir ürün ID'si ile çağrıldığında mevcut ürün verilerini yükleyecek, ID olmadan çağrıldığında ise boş bir form olarak davranacaktır. Bu ayrımı yönetmek, Next.js'in dinamik rotalama ve veri çekme yetenekleriyle oldukça basittir.

Bu yaklaşım sayesinde, yalnızca tek bir UI bileşeni tasarlayarak ve tek bir doğrulama şeması yazarak hem oluşturma hem de düzenleme işlevselliğini kapsayabiliriz. Böylece, kodun okunabilirliği, sürdürülebilirliği ve geliştirme hızı önemli ölçüde artırılmış olacaktır. Şimdi bu mimariyi nasıl kodlayacağımıza geçelim.

Uygulamalı Adımlar: Tek Form Bileşenini Geliştirmek - React Hook Form ve Zod ile Sihri Gerçekleştirmek

Tek form bileşenimizi oluşturmaya başlarken, ilk adımımız formumuzun beklediği veri yapısını Zod ile tanımlamaktır. Bu şema, hem istemci tarafında form doğrulama hem de sunucu tarafında API doğrulama için kullanılacaktır.

1. Ürün Şemasını Tanımlama (Zod)

Projenizin kök dizininde veya uygun bir konumda (örn. lib/schemas.ts) ürün şemasını tanımlayalım:


// lib/schemas.ts
import { z } from 'zod';

export const productSchema = z.object({
  name: z.string().min(3, "Ürün adı en az 3 karakter olmalı."),
  description: z.string().optional().nullable(), // Opsiyonel ve boş olabilir
  price: z.number().min(0.01, "Fiyat 0'dan büyük olmalı."),
  category: z.enum(["elektronik", "giyim", "ev", "kitap"], "Geçerli bir kategori seçin."),
  stock: z.number().int().min(0, "Stok adedi negatif olamaz."),
});

// TypeScript tipini otomatik olarak Zod şemasından türetelim
export type ProductFormData = z.infer;

Bu şema, formumuzun beklediği alanları, tiplerini ve doğrulama kurallarını açıkça belirtir. ProductFormData tipi sayesinde, form verilerimiz için güçlü bir tip güvenliği sağlamış oluruz.

2. Tek Form Bileşenini Oluşturma

Şimdi ProductForm adında bir React bileşeni oluşturalım. Bu bileşen, hem yeni ürün oluşturma hem de mevcut ürün düzenleme senaryolarını ele alacak. Bileşenimiz, düzenleme modunda olup olmadığını belirten bir initialData prop'u alacak.


// components/ProductForm.tsx
"use client"; // Bu bileşenin Client Component olduğunu belirtiriz

import React from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { productSchema, ProductFormData } from '../lib/schemas'; // Şemamızı import ediyoruz

interface ProductFormProps {
  initialData?: ProductFormData & { id?: string }; // Düzenleme için önceden doldurulacak veriler
  onSubmitSuccess: (message: string) => void;
  onSubmitError: (message: string) => void;
  isLoading: boolean;
}

const ProductForm: React.FC = ({ initialData, onSubmitSuccess, onSubmitError, isLoading }) => {
  const { register, handleSubmit, formState: { errors, isSubmitting }, reset } = useForm({
    resolver: zodResolver(productSchema),
    defaultValues: initialData || { name: '', description: '', price: 0.01, category: 'elektronik', stock: 0 },
  });

  React.useEffect(() => {
    // initialData değiştiğinde formu resetle
    reset(initialData);
  }, [initialData, reset]);

  const onSubmit = async (data: ProductFormData) => {
    try {
      const url = initialData?.id ? /api/products/${initialData.id} : '/api/products';
      const method = initialData?.id ? 'PUT' : 'POST';

      const response = await fetch(url, {
        method,
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.message || API hatası: ${response.status});
      }

      const result = await response.json();
      onSubmitSuccess(initialData?.id ? 'Ürün başarıyla güncellendi!' : 'Ürün başarıyla oluşturuldu!');
      if (!initialData?.id) {
        reset(); // Yeni ürün oluşturulduğunda formu temizle
      }
    } catch (error: any) {
      onSubmitError(error.message || 'Bir hata oluştu.');
    }
  };

  return (
    
{errors.name &&

{errors.name.message}

}
{errors.description &&

{errors.description.message}

}
{errors.price &&

{errors.price.message}

}
{errors.category &&

{errors.category.message}

}
{errors.stock &&

{errors.stock.message}

}
); }; export default ProductForm;

Yukarıdaki ProductForm bileşeninde dikkat çekici noktalar:

  • initialData prop'u: Eğer bu prop varsa, form düzenleme modundadır ve alanlar initialData ile doldurulur. Yoksa, form yeni ürün oluşturma modundadır.
  • zodResolver: React Hook Form'u Zod şemamızla entegre eder. Bu sayede, form gönderilmeden önce istemci tarafında otomatik olarak doğrulanır.
  • useEffect ile reset: initialData değiştiğinde, formun varsayılan değerlerini güncellemek için reset() fonksiyonunu kullanırız. Bu, sayfa geçişlerinde veya initialData'nın dinamik olarak yüklendiği durumlarda formun doğru verilerle başlamasını sağlar.
  • onSubmit fonksiyonu: Form gönderildiğinde, initialData.id olup olmadığına bakılarak API isteği (POST veya PUT) ve URL dinamik olarak belirlenir.
  • UI: Her input alanı için register fonksiyonunu kullanırız ve hata mesajlarını errors objesinden çekeriz.

3. Next.js Sayfalarında Formu Kullanma

Şimdi bu bileşeni Next.js sayfalarında nasıl kullanacağımızı görelim.

Yeni Ürün Oluşturma Sayfası (app/admin/products/new/page.tsx):

// app/admin/products/new/page.tsx
"use client";

import ProductForm from '../../../../components/ProductForm';
import { useState } from 'react';

export default function NewProductPage() {
  const [message, setMessage] = useState(null);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  const handleSuccess = (msg: string) => {
    setMessage(msg);
    setError(null);
    setIsLoading(false);
  };

  const handleError = (err: string) => {
    setError(err);
    setMessage(null);
    setIsLoading(false);
  };

  return (
    

Yeni Ürün Oluştur

{message &&
{message}
} {error &&
{error}
}
); }

Ürün Düzenleme Sayfası (app/admin/products/[id]/edit/page.tsx):

// app/admin/products/[id]/edit/page.tsx
"use client";

import ProductForm from '../../../../components/ProductForm';
import { ProductFormData } from '../../../../lib/schemas';
import { useState, useEffect } from 'react';
import { useParams } from 'next/navigation'; // App Router için useParams

export default function EditProductPage() {
  const params = useParams();
  const productId = params.id as string;
  const [product, setProduct] = useState(null);
  const [loadingProduct, setLoadingProduct] = useState(true);
  const [message, setMessage] = useState(null);
  const [error, setError] = useState(null);
  const [isSubmitting, setIsSubmitting] = useState(false);

  useEffect(() => {
    if (productId) {
      const fetchProduct = async () => {
        try {
          setLoadingProduct(true);
          const response = await fetch(/api/products/${productId});
          if (!response.ok) {
            throw new Error('Ürün bulunamadı veya bir hata oluştu.');
          }
          const data = await response.json();
          setProduct(data);
        } catch (err: any) {
          setError(err.message || 'Ürün yüklenirken bir hata oluştu.');
        } finally {
          setLoadingProduct(false);
        }
      };
      fetchProduct();
    }
  }, [productId]);

  const handleSuccess = (msg: string) => {
    setMessage(msg);
    setError(null);
    setIsSubmitting(false);
  };

  const handleError = (err: string) => {
    setError(err);
    setMessage(null);
    setIsSubmitting(false);
  };

  if (loadingProduct) {
    return 

Ürün bilgileri yükleniyor...

; } if (!product && !loadingProduct) { return

Düzenlenecek ürün bulunamadı.

; } return (

Ürünü Düzenle: {product?.name}

{message &&
{message}
} {error &&
{error}
} {product && ( )}
); }

Gördüğünüz gibi, her iki sayfada da aynı ProductForm bileşenini kullanıyoruz. Tek fark, düzenleme sayfasında initialData prop'unu mevcut ürün verileriyle doldurmamızdır. Bu, Next.js'in App Router yapısında client-side veri çekme örneğidir. Dilerseniz bu veri çekme işlemini Server Component içinde de yapıp ProductForm'a prop olarak geçirebilirsiniz.

API Katmanı: Next.js API Rotaları ile Veri İşleme - Sunucu Tarafında Güvenli İşlemler

Form verilerinin doğru ve güvenli bir şekilde işlenmesi için Next.js API rotalarını kullanacağız. Sunucu tarafında da Zod şemasıyla doğrulama yapmak, kötü niyetli veya hatalı veri gönderimlerine karşı ek bir güvenlik katmanı sağlar.

1. Ürün Oluşturma API Rotası (POST)

Yeni ürünler oluşturmak için bir POST rotası tanımlayalım (app/api/products/route.ts):


// app/api/products/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { productSchema } from '../../../lib/schemas';
import { v4 as uuidv4 } from 'uuid'; // Benzersiz ID oluşturmak için (npm install uuid)

// Basit bir mock veritabanı (gerçek uygulamada veritabanı entegrasyonu olur)
const products: (typeof productSchema._type & { id: string })[] = [];

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();

    // Sunucu tarafında doğrulama
    const validatedData = productSchema.parse(body);

    const newProduct = {
      id: uuidv4(),
      ...validatedData,
    };
    products.push(newProduct);

    console.log('Yeni ürün oluşturuldu:', newProduct);
    return NextResponse.json(newProduct, { status: 201 });
  } catch (error: any) {
    if (error.issues) {
      // Zod doğrulama hatası
      return NextResponse.json({ message: 'Doğrulama hatası', errors: error.issues }, { status: 400 });
    }
    console.error('Ürün oluşturulurken hata:', error);
    return NextResponse.json({ message: 'Sunucu hatası', error: error.message }, { status: 500 });
  }
}

// Bu API rotası GET isteği ile tüm ürünleri döndürsün (örnek amaçlı)
export async function GET() {
  return NextResponse.json(products);
}

Bu rotada, productSchema.parse(body) ile gelen verinin şemaya uygun olup olmadığını kontrol ediyoruz. Eğer veri geçerliyse, yeni bir ürün ID'si oluşturup ürünü mock veritabanımıza ekliyoruz.

2. Ürün Düzenleme API Rotası (PUT)

Mevcut ürünleri düzenlemek için dinamik bir PUT rotası tanımlayalım (app/api/products/[id]/route.ts):


// app/api/products/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { productSchema } from '../../../../lib/schemas';

// Mock veritabanını import ediyoruz (gerçek uygulamada veritabanından veri çekilir)
// Bu sadece örnek amaçlı, gerçekte veritabanı katmanı ayrı yönetilir.
const products: (typeof productSchema._type & { id: string })[] = []; // Aynı mock array'i kullanmalıyız

export async function GET(req: NextRequest, { params }: { params: { id: string } }) {
  const { id } = params;
  const product = products.find(p => p.id === id);

  if (!product) {
    return NextResponse.json({ message: 'Ürün bulunamadı' }, { status: 404 });
  }

  return NextResponse.json(product);
}

export async function PUT(req: NextRequest, { params }: { params: { id: string } }) {
  try {
    const { id } = params;
    const body = await req.json();

    // Sunucu tarafında doğrulama
    const validatedData = productSchema.parse(body);

    const productIndex = products.findIndex(p => p.id === id);

    if (productIndex === -1) {
      return NextResponse.json({ message: 'Güncellenecek ürün bulunamadı' }, { status: 404 });
    }

    products[productIndex] = {
      ...products[productIndex],
      ...validatedData,
      id: id, // ID'nin değişmediğinden emin olmak için
    };

    console.log('Ürün güncellendi:', products[productIndex]);
    return NextResponse.json(products[productIndex], { status: 200 });
  } catch (error: any) {
    if (error.issues) {
      // Zod doğrulama hatası
      return NextResponse.json({ message: 'Doğrulama hatası', errors: error.issues }, { status: 400 });
    }
    console.error('Ürün güncellenirken hata:', error);
    return NextResponse.json({ message: 'Sunucu hatası', error: error.message }, { status: 500 });
  }
}

Bu dinamik rotada, URL'den id parametresini alıyoruz ve gelen veriyi yine productSchema.parse(body) ile doğruluyoruz. Ardından, mock veritabanındaki ilgili ürünü güncelliyoruz. Hem POST hem de PUT rotalarında aynı Zod şemasını kullanarak, istemci ve sunucu arasında veri tutarlılığını ve doğrulama mantığını korumuş oluyoruz. Bu, geliştirme sürecini basitleştirir ve hata olasılığını azaltır. Bu güçlü yapı sayesinde, tek bir form bileşenini kullanarak hem oluşturma hem de düzenleme operasyonlarını kusursuz bir şekilde yönetebiliriz.

Gelişmiş Teknikler ve İpuçları: Performansı ve Kullanıcı Deneyimini Artırma

Tek form yaklaşımını daha da güçlendirmek ve uygulamanızın kalitesini artırmak için bazı gelişmiş teknikler ve ipuçları mevcuttur. Bu teknikler, özellikle büyük ve karmaşık formlarda performans, kullanıcı deneyimi ve geliştirici verimliliği açısından önemli faydalar sağlayabilir.

1. Debounce ve Throttling ile Performansı Optimize Etme

Bazı form alanları, örneğin arama kutuları veya anlık doğrulama gerektiren alanlar, her tuş vuruşunda bir işlem tetikleyebilir. Bu durum, özellikle API istekleri söz konusu olduğunda sunucu üzerinde gereksiz yük yaratabilir veya istemci tarafında performansı düşürebilir. Debounce ve throttling, bu tür durumları yönetmek için kullanılan iki yaygın tekniktir:

  • Debounce: Bir fonksiyonun, belirli bir süre boyunca (örn. 500ms) başka bir çağrı yapılmadığında çalışmasını sağlar. Yani, kullanıcı yazmayı bitirdiğinde işlem tetiklenir. Arama kutularında veya anlık doğrulama işlemlerinde idealdir.
  • Throttling: Bir fonksiyonun, belirli bir zaman aralığı içinde yalnızca bir kez çalışmasını sağlar. Örneğin, bir butona art arda basıldığında veya bir pencere yeniden boyutlandırıldığında, fonksiyonun sadece bir kez tetiklenmesini garanti eder.
Uzman İpucu: Lodash kütüphanesi (lodash.debounce, lodash.throttle) veya React'ın useCallback ve setTimeout/clearTimeout kombinasyonları ile debounce/throttle kolayca uygulanabilir. Özellikle form elemanlarının onChange event'inde sıkça tetiklenen validasyonlar için debouncing kullanarak daha pürüzsüz bir kullanıcı deneyimi sağlayabilirsiniz.

2. Global Durum Yönetimi ile Form Verilerini Paylaşma

Bazı durumlarda, form verilerinin veya formun gönderim durumunun, form bileşeninin dışında farklı bileşenlerle paylaşılması gerekebilir. Örneğin, bir navigasyon çubuğunda formun kaydedilmemiş değişiklikleri olduğunu gösteren bir bildirim göstermek isteyebilirsiniz. Bu senaryolar için global durum yönetimi kütüphaneleri oldukça faydalıdır:

  • Zustand veya Jotai: Hafif ve kullanımı kolay global durum yönetim kütüphaneleridir. Formun genel durumunu (örn. isDirty, isValid) bu kütüphaneler aracılığıyla farklı bileşenlere sağlayabilirsiniz.
  • React Context API: Daha az karmaşık global durum paylaşımı için React'ın kendi Context API'si yeterli olabilir. Özellikle sadece formla ilgili durumu yönetmek için idealdir.

// lib/store.ts (Zustand örneği)
import { create } from 'zustand';

interface FormState {
  isFormDirty: boolean;
  setFormDirty: (dirty: boolean) => void;
}

export const useFormStore = create((set) => ({
  isFormDirty: false,
  setFormDirty: (dirty) => set({ isFormDirty: dirty }),
}));

// Form bileşeninizde:
// import { useFormStore } from '../lib/store';
// const { formState: { isDirty } } = useForm(...);
// const setFormDirty = useFormStore(state => state.setFormDirty);
// useEffect(() => { setFormDirty(isDirty); }, [isDirty, setFormDirty]);

3. Form Resetleme ve Varsayılan Değerler

React Hook Form'un reset() fonksiyonu, formun varsayılan değerlerine geri dönmesini veya yeni değerlerle başlatılmasını sağlar. Yeni bir ürün oluşturulduğunda formu temizlemek veya düzenleme modunda vazgeçildiğinde orijinal değerlere dönmek için bu fonksiyonu akıllıca kullanmak önemlidir:

  • Yeni Oluşturma Sonrası Temizleme: Başarılı bir POST işleminden sonra, reset() fonksiyonunu parametresiz çağırarak formu başlangıç durumuna getirebilirsiniz.
  • Düzenleme Modunda İptal: Düzenleme modunda bir "İptal" butonu ekleyerek, bu butona basıldığında reset(initialData) çağırarak formu orijinal değerlerine döndürebilirsiniz.

4. Yükleme Durumları ve Hata Bildirimleri

Kullanıcı deneyimini iyileştirmek için, formun gönderildiği veya veri çekildiği sırada görsel geri bildirimler sağlamak kritik öneme sahiptir. Butonların devre dışı bırakılması, yükleme göstergeleri ve açık hata/başarı mesajları, kullanıcının ne olup bittiğini anlamasına yardımcı olur:

  • Yükleme Durumu: API isteği devam ederken submit butonunu disabled yapmak ve metnini "Gönderiliyor..." olarak değiştirmek yaygın bir yöntemdir.
  • Hata/Başarı Mesajları: API yanıtından dönen hata veya başarı mesajlarını, formun üstünde veya ilgili alanların yanında anlaşılır bir şekilde göstermek gerekir. Next.js'in useState hook'u veya global durum yönetim kütüphaneleri bu mesajları yönetmek için kullanılabilir.

5. Sıfırdan Farklı Form Alanları: Dosya Yüklemeleri ve Zengin Metin Editörleri

Bazen formlarınızda standart metin inputlarından daha fazlasına ihtiyaç duyarsınız: dosya yükleyiciler, resim seçiciler veya zengin metin editörleri gibi. React Hook Form, bu tür "kontrolsüz" veya üçüncü taraf bileşenlerini yönetmek için Controller bileşenini sunar:


import { Controller } from 'react-hook-form';
import RichTextEditor from './RichTextEditor'; // Kendi zengin metin editörünüz

 (
    
  )}
/>

Controller, üçüncü taraf bileşenlerini React Hook Form'a entegre etmenizi sağlar, böylece bu bileşenlerin değerlerini ve değişikliklerini form state'i içinde yönetebilirsiniz. Bu ileri düzey teknikler, tek form yaklaşımınızı daha sağlam, performanslı ve kullanıcı dostu hale getirmenize yardımcı olacaktır.

Vaka Analizi Sonucu ve Faydaları: Projemizde Neleri Değiştirdi?

Ürün yönetimi paneli vaka analizimizle birlikte, tek form yaklaşımının projemize getirdiği somut faydaları net bir şekilde görebiliriz. Bu strateji, sadece bir teknik uygulama olmanın ötesinde, tüm geliştirme sürecimize ve son kullanıcı deneyimine önemli katkılar sağladı.

Öncelikle, en belirgin fayda kod tekrarının dramatik bir şekilde azalmasıdır. Daha önce hem oluşturma hem de düzenleme için ayrı ayrı form bileşenleri, doğrulama mantıkları ve API entegrasyonları yazmak zorunda kalırken, şimdi tek bir ProductForm bileşeni ve tek bir Zod şeması ile tüm bu işlevselliği karşılıyoruz. Bu durum, özellikle form alanlarının sayısı veya doğrulama kurallarının karmaşıklığı arttıkça, geliştirme süresinden ve bakım maliyetlerinden önemli ölçüde tasarruf etmemizi sağladı.

İkinci olarak, geliştirme hızımız arttı. Yeni bir ürün alanı eklemek veya mevcut bir alanın doğrulama kuralını değiştirmek istediğimizde, bu değişikliği sadece bir noktada (Zod şeması ve form bileşeni) yapmamız yeterli oluyor. Bu da özellik geliştirme döngülerini kısaltıyor ve ekiplerin daha hızlı iterasyon yapmasına olanak tanıyor. Kodun tek bir merkezi yerden yönetilmesi, hata olasılığını da büyük ölçüde düşürdü, çünkü bir değişiklik yapıldığında diğer formun unutulması veya yanlış uygulanması riski ortadan kalktı.

Üçüncü olarak, kullanıcı deneyimi önemli ölçüde iyileşti. Oluşturma ve düzenleme formlarının hem görsel hem de davranışsal olarak tamamen aynı olması, kullanıcıların uygulamayı daha sezgisel bir şekilde kullanmasını sağladı. Formlar arasında geçiş yaparken herhangi bir yabancılık çekmemeleri, öğrenme eğrisini düşürdü ve genel memnuniyeti artırdı. Tutarlı hata mesajları, yükleme durumları ve varsayılan değerler, kullanıcının uygulamanın güvenilir ve profesyonel olduğu algısını güçlendirdi.

Son olarak, ekip üzerindeki pozitif etkiler de göz ardı edilemez. Geliştiriciler, daha az tekrarlayan kod yazarak daha yaratıcı ve karmaşık problemlere odaklanabildiler. Kod tabanının daha temiz ve anlaşılır olması, yeni ekip üyelerinin projeye adaptasyonunu kolaylaştırdı ve işbirliğini teşvik etti. Tek bir form bileşeni üzerinde çalışmak, farklı geliştiricilerin aynı işlevsellik üzerinde çakışma riskini de azalttı.

Kısacası, Next.js, React Hook Form ve Zod üçlüsüyle uyguladığımız tek form yaklaşımı, ürün yönetim panelimizde verimliliği, tutarlılığı ve kullanıcı memnuniyetini artırarak projemize değer kattı. Bu strateji, modern web geliştirmenin vazgeçilmez bir parçası olmaya adaydır.

Sonuç: Tek Form Yaklaşımının Geleceği ve Sıkça Sorulan Sorular

Bu makale boyunca, Next.js ekosistemi içinde React Hook Form ve Zod kütüphanelerinin gücünü birleştirerek, oluşturma ve düzenleme işlemlerini tek bir form bileşeninde nasıl birleştirebileceğimizi ayrıntılı bir şekilde ele aldık. Gördüğümüz gibi, bu "tek form" yaklaşımı, kod tekrarını azaltma, geliştirme hızını artırma, bakım maliyetlerini düşürme ve en önemlisi tutarlı bir kullanıcı deneyimi sunma gibi pek çok avantajı beraberinde getiriyor. Modern ve ölçeklenebilir web uygulamaları geliştirirken, bu stratejiyi benimsemek, hem geliştirici verimliliğini hem de son kullanıcı memnuniyetini önemli ölçüde artırabilir.

Next.js'in dinamik rotalama ve API rotaları, React Hook Form'un performanslı form yönetimi ve Zod'un tip güvenli, şema tabanlı doğrulaması, bu yaklaşımın temel taşlarını oluşturuyor. Bu araçların doğru bir şekilde entegrasyonu, karmaşık formları bile şık ve yönetilebilir hale getirmemize olanak tanıyor. Artık ayrı ayrı formlar tasarlamak yerine, tek bir güçlü ve esnek bileşenle tüm veri giriş ihtiyaçlarınızı karşılayabilirsiniz.

Bu yaklaşımı kendi projelerinizde denemekten çekinmeyin. Küçük bir modül veya basit bir veri girişi ekranıyla başlayarak, bu stratejinin sunduğu faydaları bizzat deneyimleyebilirsiniz. Unutmayın, iyi yazılmış kod sadece işlevsel olmakla kalmaz, aynı zamanda sürdürülebilir ve okunabilir olmalıdır. Tek form yaklaşımı, tam da bu hedeflere ulaşmanızda size yardımcı olacaktır.

Sıkça Sorulan Sorular

Tek form yaklaşımı her senaryoda uygun mudur?
Çoğu senaryoda uygundur, özellikle oluşturma ve düzenleme formları benzer alanlara sahipse. Ancak, eğer oluşturma formu ile düzenleme formu arasında çok büyük farklılıklar (örn. tamamen farklı alan setleri veya iş akışları) varsa, iki ayrı form tutmak daha mantıklı olabilir. Karar verirken kod tekrarı ve karmaşıklık dengesini göz önünde bulundurun.
Zod yerine başka bir doğrulama kütüphanesi kullanabilir miyim?
Evet, React Hook Form; Yup, Joi, Valibot gibi diğer doğrulama kütüphaneleriyle de entegrasyon için resolver paketleri sunar (örn. @hookform/resolvers/yup). Zod, özellikle TypeScript entegrasyonu ve güçlü şema tanımlama yetenekleri nedeniyle popüler bir seçimdir, ancak tercih size kalmıştır.
Sunucu tarafı doğrulamaya neden hala ihtiyacım var? İstemci tarafında doğrulama yapmıyor muyuz?
Evet, istemci tarafı doğrulama kullanıcı deneyimi için önemlidir (anlık geri bildirim). Ancak, kötü niyetli kullanıcılar istemci tarafı doğrulamayı atlayabilir. Bu nedenle, sunucu tarafında da aynı Zod şemasıyla doğrulama yapmak, uygulamanızın güvenliğini ve veri bütünlüğünü garanti altına almak için kritik öneme sahiptir. Bu, "güvenliğin derinliği" ilkesinin bir parçasıdır.
Formum çok büyür ve karmaşıklaşırsa ne yapmalıyım?
Çok büyük formları daha küçük, yönetilebilir parçalara (alt bileşenlere) ayırabilirsiniz. Örneğin, ProductForm içinde ProductDetailsSection, PricingSection gibi alt bileşenler oluşturabilir ve bunları register veya Controller ile ana forma bağlayabilirsiniz. Ayrıca, sekme tabanlı veya sihirbaz tarzı formlar kullanarak kullanıcı deneyimini iyileştirebilirsiniz.
Dosya yüklemeleri gibi non-standard input'ları nasıl yönetirim?
React Hook Form, Controller bileşenini veya useController hook'unu kullanarak harici veya kontrolsüz bileşenleri forma entegre etmenizi sağlar. Dosya yüklemeleri için genellikle FormData API'sini kullanarak dosyaları API'ye gönderirsiniz ve bu işlemi onSubmit metodunuz içinde manuel olarak yönetirsiniz.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Exit mobile version