Takip et

React’te Otomatik Tamamlama Bileşeni Nasıl Oluşturulur?

React’te Otomatik Tamamlama Bileşeni Nasıl Oluşturulur? Otomatik tamamlama (autocomplete) bileşenleri, modern web uygulamalarının vazgeçilmez

React’te Otomatik Tamamlama Bileşeni Nasıl Oluşturulur?

Otomatik tamamlama (autocomplete) bileşenleri, modern web uygulamalarının vazgeçilmez bir parçası haline gelmiştir. Kullanıcı deneyimini önemli ölçüde artıran bu bileşenler, kullanıcıların arama sorgularını veya metin girişlerini daha hızlı ve hatasız bir şekilde tamamlamalarına olanak tanır. Bir e-ticaret sitesinde ürün ararken, bir sosyal medya platformunda arkadaş ararken veya bir form doldururken sıkça karşılaştığımız otomatik tamamlama, kullanıcıların zamanından tasarruf etmesini ve daha akıcı bir etkileşim sağlamasını hedefler.

Bu kapsamlı teknik makalede, React kullanarak sıfırdan güçlü ve kullanıcı dostu bir otomatik tamamlama bileşeni oluşturmanın tüm adımlarını detaylı bir şekilde inceleyeceğiz. Temel yapıdan başlayarak, kullanıcı girişini yönetme, veri filtreleme, önerileri görüntüleme, klavye navigasyonu, performans optimizasyonları ve erişilebilirlik (accessibility) gibi önemli konulara değineceğiz. Kendi özel ihtiyaçlarınıza göre uyarlayabileceğiniz esnek bir bileşen inşa etmeyi öğreneceksiniz.

Otomatik Tamamlama Bileşeninin Temel Konseptleri

Bir otomatik tamamlama bileşeni, genellikle üç ana bölümden oluşur: bir metin giriş alanı (input), kullanıcının yazdıklarına göre filtrelenmiş veya API’den getirilmiş önerilerin listesi ve bu önerilerin görüntülendiği bir açılır menü. Bu bileşenin arkasındaki temel iş akışı şöyledir:

1. Kullanıcı Girişi: Kullanıcı metin giriş alanına yazmaya başlar.
2. Veri İşleme: Her karakter girişinde, bileşen kullanıcının yazdığı metni alır ve bu metni kullanarak uygun önerileri bulmak için bir veri kaynağını (yerel bir dizi, bir API veya veritabanı) sorgular.
3. Öneri Görüntüleme: Bulunan öneriler, giriş alanının altında bir açılır liste olarak görüntülenir.
4. Seçim: Kullanıcı listeden bir öneriyi tıklayarak veya klavye ile seçerek giriş alanını bu öneriyle doldurur.

Bu iş akışını React’in bildirimsel yapısı ve durum yönetimi yetenekleriyle birleştirmek, bize güçlü ve bakımı kolay bir bileşen oluşturma imkanı sunar.

React Projesini Hazırlama

Öncelikle, React projemizi oluşturarak başlayalım. Eğer zaten bir React projeniz varsa bu adımı atlayabilirsiniz. Yeni bir proje oluşturmak için create-react-app veya Vite kullanabilirsiniz. Vite, daha hızlı bir geliştirme deneyimi sunduğu için tercih edilebilir.

# Vite ile yeni bir React projesi oluşturma
npm create vite@latest my-autocomplete-app -- --template react
cd my-autocomplete-app
npm install
npm run dev

Projemizin src klasörü altında components adında bir klasör oluşturalım ve Autocomplete.jsx (veya .tsx TypeScript kullanıyorsanız) dosyamızı buraya yerleştirelim.

Temel Otomatik Tamamlama Bileşenini Oluşturma

Şimdi, otomatik tamamlama bileşenimizin temel yapısını adım adım inşa edelim. Bu bölümde, React’in useState ve useEffect hook’larını kullanarak bileşenin durumunu yönetecek ve kullanıcı etkileşimlerini ele alacağız.

Durum Yönetimi (useState)

Bir otomatik tamamlama bileşeninde yönetmemiz gereken birkaç önemli durum vardır:

* inputValue: Kullanıcının giriş alanına yazdığı metin.
* suggestions: Kullanıcının girdisine göre filtrelenmiş öneriler dizisi.
* showSuggestions: Öneri listesinin görünür olup olmadığını kontrol eden boolean değer.
* activeSuggestionIndex: Klavye ile gezinirken aktif olan önerinin dizini.
* loading: Verilerin yüklenip yüklenmediğini gösteren boolean değer (API entegrasyonu için).

// src/components/Autocomplete.jsx
import React, { useState, useEffect, useRef } from 'react';
import './Autocomplete.css'; // Stil dosyamızı da import edelim

const Autocomplete = ({ suggestionsData, onSelect }) => {
  const [inputValue, setInputValue] = useState('');
  const [suggestions, setSuggestions] = useState([]);
  const [showSuggestions, setShowSuggestions] = useState(false);
  const [activeSuggestionIndex, setActiveSuggestionIndex] = useState(-1); // -1: Hiçbiri aktif değil
  const [loading, setLoading] = useState(false); // API çağrıları için
  const inputRef = useRef(null); // Giriş alanına odaklanmak için

  // Örnek bir veri kaynağı (daha sonra API ile değiştirebiliriz)
  const defaultSuggestions = suggestionsData || [
    'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry',
    'Fig', 'Grape', 'Honeydew', 'Kiwi', 'Lemon',
    'Mango', 'Nectarine', 'Orange', 'Papaya', 'Quince',
    'Raspberry', 'Strawberry', 'Tangerine', 'Ugli Fruit', 'Vanilla Bean',
    'Watermelon', 'Xigua', 'Yellow Passion Fruit', 'Zucchini'
  ];

  // ... diğer kodlar buraya gelecek ...

  return (
    
{/ ... input ve öneri listesi buraya gelecek ... /}
); }; export default Autocomplete;

Giriş Alanı () ve Değişiklikleri Yönetme

Giriş alanı, otomatik tamamlama bileşenimizin kalbidir. Kullanıcının her tuş vuruşunda inputValue durumunu güncellememiz ve önerileri filtrelememiz gerekir.

// Autocomplete.jsx içinde, return ifadesinin içinde
 setShowSuggestions(true)} // Odaklandığında önerileri göster
  onBlur={onBlur} // Odak kaybında önerileri gizle
  placeholder="Aramak istediğiniz meyveyi yazın..."
  aria-autocomplete="list"
  aria-controls="suggestions-list"
  className="autocomplete-input"
/>

Şimdi onChange olay yöneticisini tanımlayalım:

// Autocomplete.jsx içinde, useState tanımlamalarından sonra
const onChange = (e) => {
  const userInput = e.target.value;
  setInputValue(userInput);
  setActiveSuggestionIndex(-1); // Yeni girişle birlikte aktif öneriyi sıfırla

  if (userInput.length === 0) {
    setSuggestions([]);
    setShowSuggestions(false);
    return;
  }

  // Öneri filtreleme veya API çağrısı burada yapılacak
  // Şimdilik yerel veriyi filtreleyelim
  const filteredSuggestions = defaultSuggestions.filter(
    (suggestion) =>
      suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1
  );

  setSuggestions(filteredSuggestions);
  setShowSuggestions(true);
};

onBlur olay yöneticisi, giriş alanından odak kaybedildiğinde öneri listesini gizlemek için kullanılır. Ancak, kullanıcı bir öneriye tıklamak isterse bu hemen gizlenmemelidir. Bu durumu yönetmek için küçük bir gecikme ekleyebiliriz.

const onBlur = () => {
  // Kullanıcının bir öneriye tıklaması için kısa bir gecikme ver
  setTimeout(() => {
    setShowSuggestions(false);
    setActiveSuggestionIndex(-1);
  }, 100);
};

Öneri Mantığı (Filtreleme ve API Entegrasyonu)

Önerileri filtrelemek için iki ana yaklaşım vardır:

1. Yerel Veri Filtreleme: Tüm olası öneriler istemcide mevcutsa, bunları doğrudan JavaScript ile filtreleyebiliriz. Bu, küçük ve sabit veri kümeleri için etkilidir.
2. API Entegrasyonu: Büyük veri kümeleri veya dinamik veriler için, kullanıcının girdisine göre filtrelenmiş önerileri almak üzere bir API’ye istek göndermemiz gerekir.

Yerel Veri Filtreleme

Yukarıdaki onChange fonksiyonunda zaten yerel filtrelemeyi gösterdik:

const filteredSuggestions = defaultSuggestions.filter(
  (suggestion) =>
    suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1
);
setSuggestions(filteredSuggestions);
setShowSuggestions(true);
API Entegrasyonu ve Debouncing

API entegrasyonu yaparken en önemli konulardan biri debouncing‘dir. Kullanıcı her tuş vuruşunda bir API isteği göndermek, sunucuya gereksiz yük bindirebilir ve performans sorunlarına yol açabilir. Debouncing, belirli bir süre içinde başka bir tuş vuruşu olmazsa API isteğini geciktirerek bu sorunu çözer.

Bunu uygulamak için useEffect ve setTimeout kullanabiliriz.

// Autocomplete.jsx içinde, useState tanımlamalarından sonra
useEffect(() => {
  const fetchSuggestions = async () => {
    if (inputValue.length === 0) {
      setSuggestions([]);
      setShowSuggestions(false);
      return;
    }

    setLoading(true);
    try {
      // Gerçek bir API çağrısı simülasyonu
      // const response = await fetch(/api/suggestions?query=${inputValue});
      // const data = await response.json();

      // Yerel veriyi filtreleyelim ve bir gecikme ekleyelim
      await new Promise(resolve => setTimeout(resolve, 300)); // API gecikmesi simülasyonu
      const filtered = defaultSuggestions.filter(
        (suggestion) =>
          suggestion.toLowerCase().includes(inputValue.toLowerCase())
      );
      setSuggestions(filtered);
      setShowSuggestions(true);
    } catch (error) {
      console.error("Öneriler getirilirken hata oluştu:", error);
      setSuggestions([]);
      setShowSuggestions(false);
    } finally {
      setLoading(false);
    }
  };

  // Debounce mekanizması
  const handler = setTimeout(() => {
    fetchSuggestions();
  }, 500); // 500ms gecikme

  // Cleanup fonksiyonu: Bir sonraki tuş vuruşunda önceki timeout'u temizle
  return () => {
    clearTimeout(handler);
  };
}, [inputValue, defaultSuggestions]); // inputValue veya defaultSuggestions değiştiğinde çalıştır

Bu useEffect hook’u, inputValue her değiştiğinde 500 milisaniye bekler. Eğer bu süre içinde inputValue tekrar değişirse, önceki setTimeout temizlenir ve yeni bir tane başlatılır. Bu sayede, kullanıcı hızlıca yazarken yalnızca son tuş vuruşundan sonraki 500ms’lik duraklamada API isteği gönderilir.

Not: onChange fonksiyonundaki yerel filtreleme mantığını bu useEffect içine taşımış olduk. onChange artık sadece setInputValue çağıracak.

// Güncellenmiş onChange fonksiyonu
const onChange = (e) => {
  const userInput = e.target.value;
  setInputValue(userInput);
  setActiveSuggestionIndex(-1);
  // setShowSuggestions(true); // Bu, useEffect içinde yönetilecek
};

Önerileri Görüntüleme (

    /

  • )

Öneri listesi, showSuggestions ve suggestions dizisinin boş olup olmamasına bağlı olarak koşullu olarak render edilmelidir.

// Autocomplete.jsx içinde, return ifadesinin içinde, input'tan sonra
{showSuggestions && (inputValue.length > 0 || loading) && (
  
    {loading ? (
  • Yükleniyor...
  • ) : suggestions.length ? ( suggestions.map((suggestion, index) => (
  • onClick(suggestion)} onMouseEnter={() => setActiveSuggestionIndex(index)} className={autocomplete-suggestion-item ${ index === activeSuggestionIndex ? 'active' : '' }} role="option" aria-selected={index === activeSuggestionIndex} id={suggestion-${index}} > {/ Arama terimini vurgulama /} {highlightMatch(suggestion, inputValue)}
  • )) ) : (
  • Sonuç bulunamadı.
  • )}
)}

onClick olay yöneticisi, bir öneriye tıklandığında ne olacağını belirler:

// Autocomplete.jsx içinde
const onClick = (suggestion) => {
  setInputValue(suggestion);
  setSuggestions([]);
  setShowSuggestions(false);
  setActiveSuggestionIndex(-1);
  if (onSelect) {
    onSelect(suggestion); // Üst bileşene seçimi bildir
  }
  inputRef.current.focus(); // Seçim sonrası input'a odaklan
};

highlightMatch fonksiyonu, kullanıcının arama terimini öneri içinde vurgulamak için kullanılır:

const highlightMatch = (text, query) => {
  if (!query) return text;
  const parts = text.split(new RegExp((${query}), 'gi'));
  return (
    
      {parts.map((part, index) =>
        part.toLowerCase() === query.toLowerCase() ? (
          {part}
        ) : (
          {part}
        )
      )}
    
  );
};

Klavye Navigasyonu (onKeyDown)

Klavye navigasyonu, otomatik tamamlama bileşenlerinin olmazsa olmazıdır. Kullanıcıların fare kullanmadan öneriler arasında gezinmesini ve seçim yapmasını sağlar.

// Autocomplete.jsx içinde
const onKeyDown = (e) => {
  // Öneri listesi görünür değilse klavye navigasyonu yapma
  if (!showSuggestions || suggestions.length === 0) {
    return;
  }

  // Aşağı ok tuşu
  if (e.key === 'ArrowDown') {
    e.preventDefault(); // İmlecin hareket etmesini engelle
    setActiveSuggestionIndex((prevIndex) =>
      prevIndex < suggestions.length - 1 ? prevIndex + 1 : 0
    );
  }
  // Yukarı ok tuşu
  else if (e.key === 'ArrowUp') {
    e.preventDefault(); // İmlecin hareket etmesini engelle
    setActiveSuggestionIndex((prevIndex) =>
      prevIndex > 0 ? prevIndex - 1 : suggestions.length - 1
    );
  }
  // Enter tuşu
  else if (e.key === 'Enter') {
    if (activeSuggestionIndex !== -1) {
      e.preventDefault(); // Form submit etmesini engelle
      onClick(suggestions[activeSuggestionIndex]);
    } else {
      // Eğer aktif öneri yoksa ve Enter'a basıldıysa, mevcut input değerini kabul et
      // veya bir arama tetikle
      // setSuggestions([]);
      // setShowSuggestions(false);
      // console.log("Arama tetiklendi:", inputValue);
    }
  }
  // Escape tuşu
  else if (e.key === 'Escape') {
    setShowSuggestions(false);
    setActiveSuggestionIndex(-1);
    setSuggestions([]);
  }
};

Bu onKeyDown yöneticisi, kullanıcının ArrowDown, ArrowUp, Enter ve Escape tuşlarına bastığında uygun eylemleri gerçekleştirir. Özellikle ArrowDown ve ArrowUp tuşlarında e.preventDefault() çağrısı yapmak, imlecin giriş alanında hareket etmesini engeller ve sadece öneri listesindeki seçimi değiştirir.

Kullanıcı Deneyimini (UX) ve Erişilebilirliği (Accessibility) Geliştirme

İyi bir otomatik tamamlama bileşeni sadece çalışmakla kalmaz, aynı zamanda kullanıcı dostu ve erişilebilir olmalıdır.

Erişilebilirlik (ARIA Attributes)

Web içeriği erişilebilirlik yönergeleri (WCAG) uyarınca, otomatik tamamlama bileşenlerinin ekran okuyucular ve diğer yardımcı teknolojilerle uyumlu olması önemlidir. ARIA (Accessible Rich Internet Applications) özelliklerini kullanarak bunu sağlayabiliriz:

* aria-autocomplete="list": Giriş alanının bir liste önerileri sağladığını belirtir.
* role="combobox": Giriş alanını ve ilişkili açılır listeyi birleşik bir kontrol olarak tanımlar.
* aria-controls="suggestions-list": Giriş alanının hangi elementin (öneri listesi) içeriğini kontrol ettiğini belirtir.
* role="listbox": Öneri listesini bir liste kutusu olarak tanımlar.
* role="option": Her bir öneri öğesini bir liste kutusu seçeneği olarak tanımlar.
* aria-selected="true/false": Klavye ile aktif olan önerinin seçili olduğunu belirtir.
* id ve aria-activedescendant: Giriş alanının, klavye ile gezinirken aktif olan önerinin id‘sini işaret etmesini sağlar. Bu, ekran okuyucuların aktif öğeyi doğru bir şekilde duyurmasını sağlar.

Autocomplete.jsx dosyamızda bu ARIA özelliklerini zaten ekledik:

// input elementinde
suggestion-${activeSuggestionIndex} : undefined}
  className="autocomplete-input"
/>

// ul elementinde
    {/ ... /}
  • suggestion-${index}} > {/ ... /}

aria-activedescendant özelliğini giriş alanına dinamik olarak eklemeyi unutmayın. Bu, ekran okuyucuların klavye ile gezinirken hangi önerinin vurgulandığını anlamasına yardımcı olur.

Styling (CSS)

Bileşenimizin görünümünü iyileştirmek için basit CSS stilleri ekleyelim. Autocomplete.css dosyamızı oluşturun:

/ src/components/Autocomplete.css /
.autocomplete-container {
  position: relative;
  width: 300px; / Genişliği ayarlayabilirsiniz /
  margin: 20px auto;
}

.autocomplete-input {
  width: 100%;
  padding: 10px;
  font-size: 16px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box; / Padding ve border genişliğe dahil /
}

.autocomplete-suggestions {
  position: absolute;
  top: 100%; / Giriş alanının hemen altına /
  left: 0;
  right: 0;
  border: 1px solid #eee;
  border-top: none;
  background-color: #fff;
  list-style: none;
  padding: 0;
  margin: 0;
  max-height: 200px; / Maksimum yükseklik ve kaydırma /
  overflow-y: auto;
  z-index: 1000; / Diğer elementlerin üzerinde görünmesini sağla /
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  border-radius: 0 0 4px 4px;
}

.autocomplete-suggestion-item {
  padding: 10px;
  cursor: pointer;
  border-bottom: 1px solid #f0f0f0;
}

.autocomplete-suggestion-item:last-child {
  border-bottom: none;
}

.autocomplete-suggestion-item:hover,
.autocomplete-suggestion-item.active {
  background-color: #f0f0f0;
}

.autocomplete-suggestion-item strong {
  font-weight: bold;
  color: #007bff; / Vurgulanan metin rengi /
}

.autocomplete-no-results,
.autocomplete-loading {
  padding: 10px;
  color: #666;
  font-style: italic;
  text-align: center;
}

Gelişmiş Konular ve Optimizasyonlar

Şimdiye kadar, sağlam bir otomatik tamamlama bileşeni oluşturduk. Ancak, daha da iyi hale getirmek için bazı gelişmiş konulara değinelim.

Custom Hook Kullanımı

Otomatik tamamlama mantığını daha modüler hale getirmek ve başka bileşenlerde de kullanabilmek için özel bir hook (custom hook) oluşturabiliriz. Bu, bileşenin karmaşıklığını azaltır ve kodu daha okunabilir hale getirir.

// src/hooks/useAutocomplete.js
import { useState, useEffect, useCallback } from 'react';

const useAutocomplete = (initialSuggestionsData, fetchSuggestionsApi, debounceDelay = 500) => {
  const [inputValue, setInputValue] = useState('');
  const [suggestions, setSuggestions] = useState([]);
  const [showSuggestions, setShowSuggestions] = useState(false);
  const [activeSuggestionIndex, setActiveSuggestionIndex] = useState(-1);
  const [loading, setLoading] = useState(false);

  // Veri kaynağını belirle
  const sourceSuggestions = initialSuggestionsData || [];

  // Öneri getirme veya filtreleme fonksiyonu
  const getSuggestions = useCallback(async (query) => {
    if (query.length === 0) {
      setSuggestions([]);
      setShowSuggestions(false);
      return;
    }

    setLoading(true);
    try {
      let result;
      if (fetchSuggestionsApi) {
        // API çağrısı
        result = await fetchSuggestionsApi(query);
      } else {
        // Yerel filtreleme
        result = sourceSuggestions.filter(
          (suggestion) =>
            suggestion.toLowerCase().includes(query.toLowerCase())
        );
      }
      setSuggestions(result);
      setShowSuggestions(true);
    } catch (error) {
      console.error("Öneriler getirilirken hata oluştu:", error);
      setSuggestions([]);
      setShowSuggestions(false);
    } finally {
      setLoading(false);
    }
  }, [sourceSuggestions, fetchSuggestionsApi]);

  // Debounce mekanizması için useEffect
  useEffect(() => {
    const handler = setTimeout(() => {
      getSuggestions(inputValue);
    }, debounceDelay);

    return () => {
      clearTimeout(handler);
    };
  }, [inputValue, debounceDelay, getSuggestions]);

  const handleInputChange = (e) => {
    setInputValue(e.target.value);
    setActiveSuggestionIndex(-1);
  };

  const handleSelectSuggestion = (suggestion) => {
    setInputValue(suggestion);
    setSuggestions([]);
    setShowSuggestions(false);
    setActiveSuggestionIndex(-1);
  };

  const handleKeyDown = (e, suggestionsList) => {
    if (!showSuggestions || suggestionsList.length === 0) {
      return;
    }

    if (e.key === 'ArrowDown') {
      e.preventDefault();
      setActiveSuggestionIndex((prevIndex) =>
        prevIndex < suggestionsList.length - 1 ? prevIndex + 1 : 0
      );
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      setActiveSuggestionIndex((prevIndex) =>
        prevIndex > 0 ? prevIndex - 1 : suggestionsList.length - 1
      );
    } else if (e.key === 'Enter') {
      if (activeSuggestionIndex !== -1) {
        e.preventDefault();
        handleSelectSuggestion(suggestionsList[activeSuggestionIndex]);
      }
    } else if (e.key === 'Escape') {
      setShowSuggestions(false);
      setActiveSuggestionIndex(-1);
      setSuggestions([]);
    }
  };

  const handleBlur = () => {
    setTimeout(() => {
      setShowSuggestions(false);
      setActiveSuggestionIndex(-1);
    }, 100);
  };

  return {
    inputValue,
    suggestions,
    showSuggestions,
    activeSuggestionIndex,
    loading,
    handleInputChange,
    handleSelectSuggestion,
    handleKeyDown,
    handleBlur,
    setInputValue, // Dışarıdan input değerini manuel ayarlamak için
  };
};

export default useAutocomplete;

Şimdi Autocomplete bileşenimiz bu hook’u kullanabilir:

// src/components/Autocomplete.jsx (useAutocomplete hook'u ile)
import React, { useRef } from 'react';
import useAutocomplete from '../hooks/useAutocomplete';
import './Autocomplete.css';

const Autocomplete = ({ suggestionsData, onSelect, fetchSuggestionsApi }) => {
  const inputRef = useRef(null);

  const {
    inputValue,
    suggestions,
    showSuggestions,
    activeSuggestionIndex,
    loading,
    handleInputChange,
    handleSelectSuggestion,
    handleKeyDown,
    handleBlur,
  } = useAutocomplete(suggestionsData, fetchSuggestionsApi);

  const onClick = (suggestion) => {
    handleSelectSuggestion(suggestion);
    if (onSelect) {
      onSelect(suggestion);
    }
    inputRef.current.focus();
  };

  const highlightMatch = (text, query) => {
    if (!query) return text;
    const parts = text.split(new RegExp((${query}), 'gi'));
    return (
      
        {parts.map((part, index) =>
          part.toLowerCase() === query.toLowerCase() ? (
            {part}
          ) : (
            {part}
          )
        )}
      
    );
  };

  return (
    
handleKeyDown(e, suggestions)} // Hook'a suggestions listesini geçirmeyi unutmayın onFocus={() => setShowSuggestions(true)} onBlur={handleBlur} placeholder="Aramak istediğiniz meyveyi yazın..." aria-autocomplete="list" aria-controls="suggestions-list" aria-activedescendant={activeSuggestionIndex !== -1 ? suggestion-${activeSuggestionIndex} : undefined} className="autocomplete-input" /> {showSuggestions && (inputValue.length > 0 || loading) && (
    {loading ? (
  • Yükleniyor...
  • ) : suggestions.length ? ( suggestions.map((suggestion, index) => (
  • onClick(suggestion)} onMouseEnter={() => setActiveSuggestionIndex(index)} className={autocomplete-suggestion-item ${ index === activeSuggestionIndex ? 'active' : '' }} role="option" aria-selected={index === activeSuggestionIndex} id={suggestion-${index}} > {highlightMatch(suggestion, inputValue)}
  • )) ) : (
  • Sonuç bulunamadı.
  • )}
)}
); }; export default Autocomplete;

Bu yapı, Autocomplete bileşenini sadece görsel sunumdan sorumlu hale getirirken, tüm mantığı useAutocomplete hook’una taşır.

TypeScript Desteği

Büyük projelerde veya daha sağlam kod yazmak istediğinizde TypeScript kullanmak, bileşenlerinizin ve hook’larınızın tip güvenliğini sağlamanıza yardımcı olur.

// src/types/autocomplete.d.ts
export type AutocompleteSuggestion = string; // Veya { id: string; name: string; } gibi daha karmaşık bir obje

// src/hooks/useAutocomplete.ts (örnek tip tanımlamaları)
import { useState, useEffect, useCallback } from 'react';

interface UseAutocompleteProps {
  initialSuggestionsData?: AutocompleteSuggestion[];
  fetchSuggestionsApi?: (query: string) => Promise;
  debounceDelay?: number;
}

interface UseAutocompleteReturn {
  inputValue: string;
  suggestions: AutocompleteSuggestion[];
  showSuggestions: boolean;
  activeSuggestionIndex: number;
  loading: boolean;
  handleInputChange: (e: React.ChangeEvent) => void;
  handleSelectSuggestion: (suggestion: AutocompleteSuggestion) => void;
  handleKeyDown: (e: React.KeyboardEvent, suggestionsList: AutocompleteSuggestion[]) => void;
  handleBlur: () => void;
  setInputValue: React.Dispatch>;
  setShowSuggestions: React.Dispatch>; // Dışarıdan kontrol için
  setActiveSuggestionIndex: React.Dispatch>; // Dışarıdan kontrol için
}

const useAutocomplete = ({
  initialSuggestionsData,
  fetchSuggestionsApi,
  debounceDelay = 500,
}: UseAutocompleteProps): UseAutocompleteReturn => {
  // ... (yukarıdaki useAutocomplete.js içeriği, tiplerle birlikte)
};

export default useAutocomplete;

// src/components/Autocomplete.tsx
import React, { useRef } from 'react';
import useAutocomplete from '../hooks/useAutocomplete';
import './Autocomplete.css';
import { AutocompleteSuggestion } from '../types/autocomplete';

interface AutocompleteProps {
  suggestionsData?: AutocompleteSuggestion[];
  onSelect?: (suggestion: AutocompleteSuggestion) => void;
  fetchSuggestionsApi?: (query: string) => Promise;
}

const Autocomplete: React.FC = ({ suggestionsData, onSelect, fetchSuggestionsApi }) => {
  // ... (yukarıdaki Autocomplete.jsx içeriği, tiplerle birlikte)
};

export default Autocomplete;

Bu, kodunuzu daha güvenli, hata ayıklaması kolay ve bakımı yapılabilir hale getirir.

Performans Optimizasyonları (useCallback, useMemo)

useCallback ve useMemo hook’ları, fonksiyonların ve değerlerin gereksiz yere yeniden oluşturulmasını engelleyerek React bileşenlerinin performansını artırmaya yardımcı olur. useAutocomplete hook’umuzda getSuggestions fonksiyonu için useCallback kullandık. Bu, getSuggestions fonksiyonunun yalnızca bağımlılıkları değiştiğinde yeniden oluşturulmasını sağlar, böylece useEffect içindeki handler fonksiyonunun gereksiz yere tekrar tekrar kurulmasını önler.

Bu özel durumda, useAutocomplete hook’unun içinde getSuggestions için useCallback kullanmak, useEffect‘in bağımlılık dizisindeki getSuggestions referansının sabit kalmasını sağlar ve gereksiz useEffect tetiklemelerini önler.

Üçüncü Taraf Kütüphaneler

Karmaşık otomatik tamamlama senaryoları (örneğin, çoklu seçim, gruplama, özelleştirilmiş renderlama) için sıfırdan bir bileşen oluşturmak zaman alıcı olabilir. Bu durumlarda, React Select, Downshift veya Autocomplete.js gibi popüler üçüncü taraf kütüphaneleri kullanmayı düşünebilirsiniz. Bu kütüphaneler, birçok özelliği ve erişilebilirlik gereksinimini hazır olarak sunar ve geliştirme sürecini hızlandırabilir. Ancak, bu makalenin amacı kendi bileşeninizi nasıl oluşturacağınızı öğretmek olduğu için, bu kütüphanelerin detaylarına girmedik.

Bileşeni Kullanma

Son olarak, App.jsx dosyamızda Autocomplete bileşenimizi nasıl kullanacağımızı görelim.

// src/App.jsx
import React from 'react';
import Autocomplete from './components/Autocomplete';

const App = () => {
  const handleFruitSelect = (selectedFruit) => {
    console.log('Seçilen meyve:', selectedFruit);
    // Burada seçilen meyve ile ilgili başka işlemler yapabilirsiniz
  };

  // Yerel veri kaynağı
  const fruits = [
    'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry',
    'Fig', 'Grape', 'Honeydew', 'Kiwi', 'Lemon',
    'Mango', 'Nectarine', 'Orange', 'Papaya', 'Quince',
    'Raspberry', 'Strawberry', 'Tangerine', 'Ugli Fruit', 'Vanilla Bean',
    'Watermelon', 'Xigua', 'Yellow Passion Fruit', 'Zucchini'
  ];

  // API'den veri getirme fonksiyonu örneği
  const fetchCountries = async (query) => {
    if (query.length < 2) return []; // En az 2 karakter girilince ara
    const response = await fetch(https://restcountries.com/v3.1/name/${query});
    const data = await response.json();
    if (response.ok && Array.isArray(data)) {
      return data.map(country => country.name.common);
    }
    return [];
  };

  return (
    

Meyve Arama (Yerel Veri)

Ülke Arama (API Entegrasyonu)

En az 2 karakter girin.

console.log('Seçilen ülke:', selectedCountry)} />
); }; export default App;

Bu örnekte, aynı Autocomplete bileşenini hem yerel bir veri kaynağıyla (meyveler) hem de harici bir API ile (ülkeler) kullanabiliyoruz. fetchSuggestionsApi prop’unu geçirerek API entegrasyonunu devreye sokmuş oluyoruz.

Sonuç

Bu makalede, React kullanarak sıfırdan güçlü, esnek ve erişilebilir bir otomatik tamamlama bileşeni oluşturmanın tüm aşamalarını detaylı bir şekilde inceledik. Kullanıcı girişini yönetmekten, veri filtrelemeye, klavye navigasyonuna, performans optimizasyonlarına ve erişilebilirlik standartlarına uymaya kadar birçok önemli konuyu ele aldık.

Kendi otomatik tamamlama bileşeninizi oluşturmak, React’in temel prensiplerini (durum yönetimi, yaşam döngüsü hook’ları, olay yönetimi) derinlemesine anlamanıza yardımcı olur ve size özel ihtiyaçlarınıza göre tamamen özelleştirilebilir bir çözüm sunar. Edindiğiniz bu bilgilerle, sadece otomatik tamamlama değil, aynı zamanda diğer karmaşık UI bileşenlerini de benzer prensiplerle inşa edebilirsiniz. Unutmayın, iyi bir kullanıcı deneyimi ve erişilebilirlik, her modern web uygulamasının temelidir.

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

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.