Frontend Development

Gerçek Zamanlı Veri Senkronizasyonunu Ustalaşmak: WebSockets ve React Query Entegrasyonu

Modern frontend geliştirme alanında, canlı ve anlık verileri görüntüleme yeteneği artık bir lüks değil, standart bir beklentidir. Finansal panellerden işbirlikli düzenleme araçlarına kadar kullanıcılar anında geri bildirim talep etmektedir. Polling yöntemi ise eski ve verimsiz bir yaklaşım iken, WebSockets bu sorunu zarif bir şekilde çözen kalıcı, çift yönlü bir iletişim kanalı sağlar. Ancak, bir React uygulaması içinde WebSocket durumunu yönetmek hızla karmaşıklaşabilir. İşte tam da burada React Query (artık TanStack Query olarak bilinir) öne çıkar; sunucu durumunu çekmek ve önbelleğe almak için sağlam bir çözüm sunar. Bu yazıda, bu iki teknolojiyi birleştirerek sorunsuz bir gerçek zamanlı deneyim nasıl oluşturulacağını keşfedeceğiz.

Durum Senkronizasyonunun Zorluğu

React Query, istek tabanlı veri çekme işlemlerini (HTTP/REST) yönetmede mükemmeldir. Önbellekleme için useQuery ve yan etkiler için useMutation gibi hook'lar sağlar. Ancak WebSockets, istek-yanıt döngüsü yerine olaya dayalı bir model üzerinde çalışır. Bu mimari uyumsuzluk, geliştiricileri genellikle React Query'yi tamamen atlayıp WebSocket aboneliklerini useEffect hook'ları içinde manuel olarak yönetmeye iter. Bu yaklaşım, uygulama ölçeklendikçe hızla yönetilemez hale gelir; yarış durumlarına, bellek sızıntılarına ve tutarsız UI durumlarına yol açar.

Amaç, güncellemeler için taşıma katmanı olarak WebSockets kullanırken React Query'nin güçlü önbellekleme ve geçersiz kılma mekanizmalarından yararlanmaktır. WebSockets'in bir bildirim görevi görerek React Query'nin veriyi yeniden çekmesini veya önbelleğini doğrudan güncellemesini tetiklediği bir stratejiye ihtiyacımız var.

WebSocket İstemcisini Kurma

İlk olarak, basit bir WebSocket istemcisi oluşturalım. Bağlantı yaşam döngüsünü yöneten özel bir hook oluşturacağız. Bu hook, bağlantıyı açmayı, mesaj göndermeyi ve gelen olayları dinlemeyi ele almalıdır.

import { useEffect, useRef } from 'react';

export const useWebSocket = (url, onMessage) => {
  const ws = useRef(null);

  useEffect(() => {
    ws.current = new WebSocket(url);

    ws.current.onopen = () => console.log('Connected');
    
    ws.current.onmessage = (event) => {
      const data = JSON.parse(event.data);
      if (onMessage) onMessage(data);
    };

    ws.current.onclose = () => console.log('Disconnected');

    return () => ws.current.close();
  }, [url, onMessage]);

  const sendMessage = (message) => {
    if (ws.current?.readyState === WebSocket.OPEN) {
      ws.current.send(JSON.stringify(message));
    }
  };

  return sendMessage;
};

WebSockets'i React Query ile Birleştirme

En etkili desen, WebSockets'i önbellek geçersiz kılmalarını tetiklemek için kullanmaktır. Bir WebSocket mesajı verinin değiştiğini belirttiğinde, queryClient.invalidateQueries() çağrısı yapabiliriz. Bu, React Query'ye önbelleğe alınmış verinin eski olduğunu ve standart HTTP uç noktası üzerinden sunucudan yeniden çekilmesi gerektiğini söyler.

Gerçek zamanlı sohbet mesajlarını çeken bir bileşene bunu nasıl entegre edebileceğinize dair bir örnek:

import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useWebSocket } from './useWebSocket';

const fetchMessages = async () => {
  const response = await fetch('/api/messages');
  return response.json();
};

const RealTimeChat = () => {
  const queryClient = useQueryClient();

  const { data, isLoading } = useQuery({
    queryKey: ['messages'],
    queryFn: fetchMessages,
  });

  // Yeni mesajları dinlemek için WebSockets kullan
  const sendMessage = useWebSocket('wss://api.example.com/chat', (msg) => {
    if (msg.type === 'NEW_MESSAGE') {
      // En son veriyi yeniden çekmek için sorguyu geçersiz kıl
      queryClient.invalidateQueries({ queryKey: ['messages'] });
      
      // Alternatif olarak, daha iyi bir kullanıcı deneyimi için önbelleği iyimser bir şekilde güncelleyebilirsiniz:
      // queryClient.setQueryData(['messages'], old => [...old, msg.payload]);
    }
  });

  if (isLoading) return <p>Loading...</p>;

  return (
    <div>
      {data.map(msg => <p key={msg.id}>{msg.text}</p>)}
      <button onClick={() => sendMessage({ type: 'SEND', text: 'Hello' })}>
        Send
      </button>
    </div>
  );
};

Daha İyi Kullanıcı Deneyimi İçin İyimser Güncellemeler

Geçersiz kılma çalışsa da, veri yeniden çekilirken kısa bir titremeye neden olur. Daha akıcı bir deneyim için iyimser güncellemeler için queryClient.setQueryData() kullanmayı düşünün. Bir mesaj alındığında, yeni öğeyle önbelleği manuel olarak güncelleyebilirsiniz. Bu, bir ağ isteği beklenmeden kullanıcıya anında geri bildirim sağlar. Her zaman sunucuyu doğruluk kaynağı olarak tutmak için, potansiyel çakışmaları çözmek amacıyla ara sıra yeniden çekim yapmayı unutmayın.

Sonuç

WebSockets'i React Query ile entegre etmek acı verici olmak zorunda değildir. WebSockets'i bir veri çekme katmanı yerine bir bildirim katmanı olarak ele alarak, React Query'nin önbellek yönetiminin sadeliğini ve gücünü koruyabilirsiniz. Bu hibrit yaklaşım, uygulamalarınızın hem performanslı hem de duyarlı olmasını sağlar; kullanıcıların beklediği gerçek zamanlı yetenekleri sunarken kod tabanınızı sürdürülebilir hale getirir. Bu deseni benimserken, ağ güvenilirliğini her zaman göz önünde bulundurun ve sağlam bir kullanıcı deneyimi sağlamak için yeniden bağlanma mantığı uygulayın.

Share: