Frontend08.06.20264 dk okuma1

Asenkron İstekler Nedir? React ve Node.js ile Sayfa Yenilemeden Veri Silme

Asenkron isteklerin modern web uygulamalarında nasıl çalıştığını React + Vite ve Node.js + Express örneği üzerinden anlatıyoruz. Sayfa yenilemeden sunucuya istek gönderme, JSON cevap alma ve React state’ini güncelleme mantığını adım adım inceliyoruz.

#react#vite#javascript#fetch#node.js#express#json

Modern web uygulamalarında genellikle iki ayrı taraf vardır:

  • Client: Kullanıcının gördüğü arayüz. Bizim örneğimizde React + Vite.

  • Server: Verilerin işlendiği arka uç. Bizim örneğimizde Node.js + Express.

Asenkron istek, tarayıcının sunucuya bir istek gönderirken sayfanın tamamen yenilenmesini beklemeden çalışmaya devam edebilmesidir. İstek arka planda tamamlanır; cevap geldiğinde JavaScript bu cevabı kullanarak arayüzü günceller.

Klasik yaklaşımda kullanıcı bir işlem yaptığında tarayıcı sunucuya istek gönderir, sunucu da yeni bir HTML sayfası döndürür. Örneğin bir ürünü silmek istediğimizde sayfa yeniden yüklenir ve ürünün olmadığı yeni sayfa gösterilir.

Bu yöntem çalışır, fakat modern uygulamalarda her işlem için sayfayı yenilemek iyi bir kullanıcı deneyimi değildir. Bunun yerine JavaScript ile arka planda istek göndeririz. Sunucu işlemi yapar, bize genellikle JSON formatında cevap döner. React de bu cevaba göre ekrandaki veriyi günceller.

İşte buna web uygulaması açısından asenkron istek diyebiliriz.

Örneğin kullanıcı bir ürünü silmek istediğinde akış şöyle olur:

  1. Kullanıcı “Sil” butonuna tıklar.

  2. React bu tıklamayı yakalar.

  3. React, ürünün id bilgisini kullanarak sunucuya istek gönderir.

  4. Sunucu ürünü siler.

  5. Sunucu JSON cevap döner.

  6. React, sayfayı yenilemeden ürünü ekrandan kaldırır.

Yani önemli fark şudur:

Sayfa yeniden yüklenmez. Sadece gerekli veri güncellenir.

Basit bir örnek üzerinden gidelim.

Backend tarafında ürünleri tutan basit bir Express uygulamamız olsun:

import express from 'express';
import cors from 'cors';

const app = express();

app.use(cors());
app.use(express.json());

let products = [
  { id: '1', title: 'Laptop', price: 30000 },
  { id: '2', title: 'Telefon', price: 20000 },
  { id: '3', title: 'Klavye', price: 1500 }
];

app.get('/products', (req, res) => {
  res.json({ products });
});

app.delete('/products/:id', (req, res) => {
  const productId = req.params.id;

  products = products.filter(product => product.id !== productId);

  res.json({
    message: 'Ürün başarıyla silindi.',
    productId
  });
});

app.listen(3000, () => {
  console.log('Server 3000 portunda çalışıyor.');
});

JSON, client ile server arasında veri taşımak için kullanılan hafif bir formattır. React tarafı HTML sayfası beklemez; sadece gelen veriyi alır ve buna göre state’i günceller.

Burada dikkat etmemiz gereken şey şu: DELETE /products/:id isteği geldiğinde sunucu yeni bir HTML sayfası döndürmüyor. Sadece JSON cevap dönüyor.

React + Vite tarafında ise ürünleri listeleyip silme işlemini şöyle yapabiliriz:

import { useEffect, useState } from 'react';

function App() {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    fetch('http://localhost:3000/products')
      .then(response => response.json())
      .then(data => {
        setProducts(data.products);
      });
  }, []);

const deleteProductHandler = async productId => {
  const response = await fetch(`http://localhost:3000/products/${productId}`, {
    method: 'DELETE'
  });

  if (!response.ok) {
    console.log('Ürün silinirken bir hata oluştu.');
    return;
  }

  const data = await response.json();

  setProducts(prevProducts => {
    return prevProducts.filter(product => product.id !== productId);
  });

  console.log(data.message);
};

  return (
    <main>
      <h1>Ürünler</h1>

      <ul>
        {products.map(product => (
          <li key={product.id}>
            <strong>{product.title}</strong> - {product.price} TL

            <button onClick={() => deleteProductHandler(product.id)}>
              Sil
            </button>
          </li>
        ))}
      </ul>
    </main>
  );
}

export default App;

response.ok, sunucudan dönen cevabın başarılı olup olmadığını kontrol eder. Böylece işlem başarısızsa ürünü ekrandan yanlışlıkla kaldırmamış oluruz.

React’te ürün listesi state üzerinden yönetilir. Listeyi render ederken her ürünün id bilgisine zaten sahip olduğumuz için, silme işleminde bu ID’yi doğrudan fonksiyona gönderebiliriz.

<button onClick={() => deleteProductHandler(product.id)}>
  Sil
</button>

Butona tıklanınca ilgili ürünün ID’sini fonksiyona gönderiyoruz. Sonra fetch ile backend’e asenkron istek atıyoruz:

await fetch(`http://localhost:3000/products/${productId}`, {
  method: 'DELETE'
});

fetch fonksiyonu bize bir Promise döndürür. Yani istek başlatılır, fakat cevap hemen gelmeyebilir. Bu sırada tarayıcı çalışmaya devam eder. Cevap geldiğinde await satırından sonraki kod çalışır. Bu yüzden bu işlem asenkron ilerler.

Sunucu ürünü sildikten sonra React tarafında state’i güncelliyoruz:

setProducts(prevProducts => {
  return prevProducts.filter(product => product.id !== productId);
});

Bu satır sayesinde React ürün listesini yeniden hesaplar ve silinen ürün ekrandan kaybolur. Ama burada tüm sayfa yenilenmez. Sadece React component’i güncellenir.

Gerçek projelerde sunucudan gelen cevabın başarılı olup olmadığını kontrol etmek gerekir. Çünkü istek gönderilmiş olsa bile işlem sunucuda başarısız olabilir.

Sonuç olarak asenkron istekler, React uygulamalarının temel taşlarından biridir. Kullanıcı bir işlem yaptığında uygulama arka planda sunucuyla konuşur, sonucu alır ve sadece gerekli alanı günceller. Bu da daha hızlı, daha akıcı ve modern bir kullanıcı deneyimi sağlar.