{"id":32449,"date":"2025-10-21T23:41:06","date_gmt":"2025-10-21T20:41:06","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/?p=32449"},"modified":"2025-10-21T23:41:06","modified_gmt":"2025-10-21T20:41:06","slug":"reactte-otomatik-tamamlama-bileseni-nasil-olusturulur","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/","title":{"rendered":"React&#8217;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?"},"content":{"rendered":"<p><body><\/p>\n<h2>React&#8217;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?<\/h2>\n<p>Otomatik tamamlama (autocomplete) bile\u015fenleri, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmez bir par\u00e7as\u0131 haline gelmi\u015ftir. Kullan\u0131c\u0131 deneyimini \u00f6nemli \u00f6l\u00e7\u00fcde art\u0131ran bu bile\u015fenler, kullan\u0131c\u0131lar\u0131n arama sorgular\u0131n\u0131 veya metin giri\u015flerini daha h\u0131zl\u0131 ve hatas\u0131z bir \u015fekilde tamamlamalar\u0131na olanak tan\u0131r. Bir e-ticaret sitesinde \u00fcr\u00fcn ararken, bir sosyal medya platformunda arkada\u015f ararken veya bir form doldururken s\u0131k\u00e7a kar\u015f\u0131la\u015ft\u0131\u011f\u0131m\u0131z otomatik tamamlama, kullan\u0131c\u0131lar\u0131n zaman\u0131ndan tasarruf etmesini ve daha ak\u0131c\u0131 bir etkile\u015fim sa\u011flamas\u0131n\u0131 hedefler.<\/p>\n<p>Bu kapsaml\u0131 teknik makalede, React kullanarak s\u0131f\u0131rdan g\u00fc\u00e7l\u00fc ve kullan\u0131c\u0131 dostu bir otomatik tamamlama bile\u015feni olu\u015fturman\u0131n t\u00fcm ad\u0131mlar\u0131n\u0131 detayl\u0131 bir \u015fekilde inceleyece\u011fiz. Temel yap\u0131dan ba\u015flayarak, kullan\u0131c\u0131 giri\u015fini y\u00f6netme, veri filtreleme, \u00f6nerileri g\u00f6r\u00fcnt\u00fcleme, klavye navigasyonu, performans optimizasyonlar\u0131 ve eri\u015filebilirlik (accessibility) gibi \u00f6nemli konulara de\u011finece\u011fiz. Kendi \u00f6zel ihtiya\u00e7lar\u0131n\u0131za g\u00f6re uyarlayabilece\u011finiz esnek bir bile\u015fen in\u015fa etmeyi \u00f6\u011freneceksiniz.<\/p>\n<h3>Otomatik Tamamlama Bile\u015feninin Temel Konseptleri<\/h3>\n<p>Bir otomatik tamamlama bile\u015feni, genellikle \u00fc\u00e7 ana b\u00f6l\u00fcmden olu\u015fur: bir metin giri\u015f alan\u0131 (input), kullan\u0131c\u0131n\u0131n yazd\u0131klar\u0131na g\u00f6re filtrelenmi\u015f veya API&#8217;den getirilmi\u015f \u00f6nerilerin listesi ve bu \u00f6nerilerin g\u00f6r\u00fcnt\u00fclendi\u011fi bir a\u00e7\u0131l\u0131r men\u00fc. Bu bile\u015fenin arkas\u0131ndaki temel i\u015f ak\u0131\u015f\u0131 \u015f\u00f6yledir:<\/p>\n<p>1.  <strong>Kullan\u0131c\u0131 Giri\u015fi:<\/strong> Kullan\u0131c\u0131 metin giri\u015f alan\u0131na yazmaya ba\u015flar.<br \/>\n2.  <strong>Veri \u0130\u015fleme:<\/strong> Her karakter giri\u015finde, bile\u015fen kullan\u0131c\u0131n\u0131n yazd\u0131\u011f\u0131 metni al\u0131r ve bu metni kullanarak uygun \u00f6nerileri bulmak i\u00e7in bir veri kayna\u011f\u0131n\u0131 (yerel bir dizi, bir API veya veritaban\u0131) sorgular.<br \/>\n3.  <strong>\u00d6neri G\u00f6r\u00fcnt\u00fcleme:<\/strong> Bulunan \u00f6neriler, giri\u015f alan\u0131n\u0131n alt\u0131nda bir a\u00e7\u0131l\u0131r liste olarak g\u00f6r\u00fcnt\u00fclenir.<br \/>\n4.  <strong>Se\u00e7im:<\/strong> Kullan\u0131c\u0131 listeden bir \u00f6neriyi t\u0131klayarak veya klavye ile se\u00e7erek giri\u015f alan\u0131n\u0131 bu \u00f6neriyle doldurur.<\/p>\n<p>Bu i\u015f ak\u0131\u015f\u0131n\u0131 React&#8217;in bildirimsel yap\u0131s\u0131 ve durum y\u00f6netimi yetenekleriyle birle\u015ftirmek, bize g\u00fc\u00e7l\u00fc ve bak\u0131m\u0131 kolay bir bile\u015fen olu\u015fturma imkan\u0131 sunar.<\/p>\n<h3>React Projesini Haz\u0131rlama<\/h3>\n<p>\u00d6ncelikle, React projemizi olu\u015fturarak ba\u015flayal\u0131m. E\u011fer zaten bir React projeniz varsa bu ad\u0131m\u0131 atlayabilirsiniz. Yeni bir proje olu\u015fturmak i\u00e7in <code>create-react-app<\/code> veya Vite kullanabilirsiniz. Vite, daha h\u0131zl\u0131 bir geli\u015ftirme deneyimi sundu\u011fu i\u00e7in tercih edilebilir.<\/p>\n<pre><code class=\"language-bash\"># Vite ile yeni bir React projesi olu\u015fturma\nnpm create vite@latest my-autocomplete-app -- --template react\ncd my-autocomplete-app\nnpm install\nnpm run dev<\/code><\/pre>\n<p>Projemizin <code>src<\/code> klas\u00f6r\u00fc alt\u0131nda <code>components<\/code> ad\u0131nda bir klas\u00f6r olu\u015ftural\u0131m ve <code>Autocomplete.jsx<\/code> (veya <code>.tsx<\/code> TypeScript kullan\u0131yorsan\u0131z) dosyam\u0131z\u0131 buraya yerle\u015ftirelim.<\/p>\n<h3>Temel Otomatik Tamamlama Bile\u015fenini Olu\u015fturma<\/h3>\n<p>\u015eimdi, otomatik tamamlama bile\u015fenimizin temel yap\u0131s\u0131n\u0131 ad\u0131m ad\u0131m in\u015fa edelim. Bu b\u00f6l\u00fcmde, React&#8217;in <code>useState<\/code> ve <code>useEffect<\/code> hook&#8217;lar\u0131n\u0131 kullanarak bile\u015fenin durumunu y\u00f6netecek ve kullan\u0131c\u0131 etkile\u015fimlerini ele alaca\u011f\u0131z.<\/p>\n<h4>Durum Y\u00f6netimi (<code>useState<\/code>)<\/h4>\n<p>Bir otomatik tamamlama bile\u015feninde y\u00f6netmemiz gereken birka\u00e7 \u00f6nemli durum vard\u0131r:<\/p>\n<p>*   <code>inputValue<\/code>: Kullan\u0131c\u0131n\u0131n giri\u015f alan\u0131na yazd\u0131\u011f\u0131 metin.<br \/>\n*   <code>suggestions<\/code>: Kullan\u0131c\u0131n\u0131n girdisine g\u00f6re filtrelenmi\u015f \u00f6neriler dizisi.<br \/>\n*   <code>showSuggestions<\/code>: \u00d6neri listesinin g\u00f6r\u00fcn\u00fcr olup olmad\u0131\u011f\u0131n\u0131 kontrol eden boolean de\u011fer.<br \/>\n*   <code>activeSuggestionIndex<\/code>: Klavye ile gezinirken aktif olan \u00f6nerinin dizini.<br \/>\n*   <code>loading<\/code>: Verilerin y\u00fcklenip y\u00fcklenmedi\u011fini g\u00f6steren boolean de\u011fer (API entegrasyonu i\u00e7in).<\/p>\n<pre><code class=\"language-jsx\">\/\/ src\/components\/Autocomplete.jsx\nimport React, { useState, useEffect, useRef } from 'react';\nimport '.\/Autocomplete.css'; \/\/ Stil dosyam\u0131z\u0131 da import edelim\n\nconst Autocomplete = ({ suggestionsData, onSelect }) => {\n  const [inputValue, setInputValue] = useState('');\n  const [suggestions, setSuggestions] = useState([]);\n  const [showSuggestions, setShowSuggestions] = useState(false);\n  const [activeSuggestionIndex, setActiveSuggestionIndex] = useState(-1); \/\/ -1: Hi\u00e7biri aktif de\u011fil\n  const [loading, setLoading] = useState(false); \/\/ API \u00e7a\u011fr\u0131lar\u0131 i\u00e7in\n  const inputRef = useRef(null); \/\/ Giri\u015f alan\u0131na odaklanmak i\u00e7in\n\n  \/\/ \u00d6rnek bir veri kayna\u011f\u0131 (daha sonra API ile de\u011fi\u015ftirebiliriz)\n  const defaultSuggestions = suggestionsData || [\n    'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry',\n    'Fig', 'Grape', 'Honeydew', 'Kiwi', 'Lemon',\n    'Mango', 'Nectarine', 'Orange', 'Papaya', 'Quince',\n    'Raspberry', 'Strawberry', 'Tangerine', 'Ugli Fruit', 'Vanilla Bean',\n    'Watermelon', 'Xigua', 'Yellow Passion Fruit', 'Zucchini'\n  ];\n\n  \/\/ ... di\u011fer kodlar buraya gelecek ...\n\n  return (\n    <div className=\"autocomplete-container\">\n      {\/<em> ... input ve \u00f6neri listesi buraya gelecek ... <\/em>\/}\n    <\/div>\n  );\n};\n\nexport default Autocomplete;<\/code><\/pre>\n<h4>Giri\u015f Alan\u0131 (<code><input><\/code>) ve De\u011fi\u015fiklikleri Y\u00f6netme<\/h4>\n<p>Giri\u015f alan\u0131, otomatik tamamlama bile\u015fenimizin kalbidir. Kullan\u0131c\u0131n\u0131n her tu\u015f vuru\u015funda <code>inputValue<\/code> durumunu g\u00fcncellememiz ve \u00f6nerileri filtrelememiz gerekir.<\/p>\n<pre><code class=\"language-jsx\">\/\/ Autocomplete.jsx i\u00e7inde, return ifadesinin i\u00e7inde\n<input\n  type=\"text\"\n  ref={inputRef}\n  value={inputValue}\n  onChange={onChange}\n  onKeyDown={onKeyDown}\n  onFocus={() => setShowSuggestions(true)} \/\/ Odakland\u0131\u011f\u0131nda \u00f6nerileri g\u00f6ster\n  onBlur={onBlur} \/\/ Odak kayb\u0131nda \u00f6nerileri gizle\n  placeholder=\"Aramak istedi\u011finiz meyveyi yaz\u0131n...\"\n  aria-autocomplete=\"list\"\n  aria-controls=\"suggestions-list\"\n  className=\"autocomplete-input\"\n\/><\/code><\/pre>\n<p>\u015eimdi <code>onChange<\/code> olay y\u00f6neticisini tan\u0131mlayal\u0131m:<\/p>\n<pre><code class=\"language-jsx\">\/\/ Autocomplete.jsx i\u00e7inde, useState tan\u0131mlamalar\u0131ndan sonra\nconst onChange = (e) => {\n  const userInput = e.target.value;\n  setInputValue(userInput);\n  setActiveSuggestionIndex(-1); \/\/ Yeni giri\u015fle birlikte aktif \u00f6neriyi s\u0131f\u0131rla\n\n  if (userInput.length === 0) {\n    setSuggestions([]);\n    setShowSuggestions(false);\n    return;\n  }\n\n  \/\/ \u00d6neri filtreleme veya API \u00e7a\u011fr\u0131s\u0131 burada yap\u0131lacak\n  \/\/ \u015eimdilik yerel veriyi filtreleyelim\n  const filteredSuggestions = defaultSuggestions.filter(\n    (suggestion) =>\n      suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1\n  );\n\n  setSuggestions(filteredSuggestions);\n  setShowSuggestions(true);\n};<\/code><\/pre>\n<p><code>onBlur<\/code> olay y\u00f6neticisi, giri\u015f alan\u0131ndan odak kaybedildi\u011finde \u00f6neri listesini gizlemek i\u00e7in kullan\u0131l\u0131r. Ancak, kullan\u0131c\u0131 bir \u00f6neriye t\u0131klamak isterse bu hemen gizlenmemelidir. Bu durumu y\u00f6netmek i\u00e7in k\u00fc\u00e7\u00fck bir gecikme ekleyebiliriz.<\/p>\n<pre><code class=\"language-jsx\">const onBlur = () => {\n  \/\/ Kullan\u0131c\u0131n\u0131n bir \u00f6neriye t\u0131klamas\u0131 i\u00e7in k\u0131sa bir gecikme ver\n  setTimeout(() => {\n    setShowSuggestions(false);\n    setActiveSuggestionIndex(-1);\n  }, 100);\n};<\/code><\/pre>\n<h4>\u00d6neri Mant\u0131\u011f\u0131 (Filtreleme ve API Entegrasyonu)<\/h4>\n<p>\u00d6nerileri filtrelemek i\u00e7in iki ana yakla\u015f\u0131m vard\u0131r:<\/p>\n<p>1.  <strong>Yerel Veri Filtreleme:<\/strong> T\u00fcm olas\u0131 \u00f6neriler istemcide mevcutsa, bunlar\u0131 do\u011frudan JavaScript ile filtreleyebiliriz. Bu, k\u00fc\u00e7\u00fck ve sabit veri k\u00fcmeleri i\u00e7in etkilidir.<br \/>\n2.  <strong>API Entegrasyonu:<\/strong> B\u00fcy\u00fck veri k\u00fcmeleri veya dinamik veriler i\u00e7in, kullan\u0131c\u0131n\u0131n girdisine g\u00f6re filtrelenmi\u015f \u00f6nerileri almak \u00fczere bir API&#8217;ye istek g\u00f6ndermemiz gerekir.<\/p>\n<h5>Yerel Veri Filtreleme<\/h5>\n<p>Yukar\u0131daki <code>onChange<\/code> fonksiyonunda zaten yerel filtrelemeyi g\u00f6sterdik:<\/p>\n<pre><code class=\"language-javascript\">const filteredSuggestions = defaultSuggestions.filter(\n  (suggestion) =>\n    suggestion.toLowerCase().indexOf(userInput.toLowerCase()) > -1\n);\nsetSuggestions(filteredSuggestions);\nsetShowSuggestions(true);<\/code><\/pre>\n<h5>API Entegrasyonu ve Debouncing<\/h5>\n<p>API entegrasyonu yaparken en \u00f6nemli konulardan biri <strong>debouncing<\/strong>&#8216;dir. Kullan\u0131c\u0131 her tu\u015f vuru\u015funda bir API iste\u011fi g\u00f6ndermek, sunucuya gereksiz y\u00fck bindirebilir ve performans sorunlar\u0131na yol a\u00e7abilir. Debouncing, belirli bir s\u00fcre i\u00e7inde ba\u015fka bir tu\u015f vuru\u015fu olmazsa API iste\u011fini geciktirerek bu sorunu \u00e7\u00f6zer.<\/p>\n<p>Bunu uygulamak i\u00e7in <code>useEffect<\/code> ve <code>setTimeout<\/code> kullanabiliriz.<\/p>\n<pre><code class=\"language-jsx\">\/\/ Autocomplete.jsx i\u00e7inde, useState tan\u0131mlamalar\u0131ndan sonra\nuseEffect(() => {\n  const fetchSuggestions = async () => {\n    if (inputValue.length === 0) {\n      setSuggestions([]);\n      setShowSuggestions(false);\n      return;\n    }\n\n    setLoading(true);\n    try {\n      \/\/ Ger\u00e7ek bir API \u00e7a\u011fr\u0131s\u0131 sim\u00fclasyonu\n      \/\/ const response = await fetch(<code>\/api\/suggestions?query=${inputValue}<\/code>);\n      \/\/ const data = await response.json();\n\n      \/\/ Yerel veriyi filtreleyelim ve bir gecikme ekleyelim\n      await new Promise(resolve => setTimeout(resolve, 300)); \/\/ API gecikmesi sim\u00fclasyonu\n      const filtered = defaultSuggestions.filter(\n        (suggestion) =>\n          suggestion.toLowerCase().includes(inputValue.toLowerCase())\n      );\n      setSuggestions(filtered);\n      setShowSuggestions(true);\n    } catch (error) {\n      console.error(\"\u00d6neriler getirilirken hata olu\u015ftu:\", error);\n      setSuggestions([]);\n      setShowSuggestions(false);\n    } finally {\n      setLoading(false);\n    }\n  };\n\n  \/\/ Debounce mekanizmas\u0131\n  const handler = setTimeout(() => {\n    fetchSuggestions();\n  }, 500); \/\/ 500ms gecikme\n\n  \/\/ Cleanup fonksiyonu: Bir sonraki tu\u015f vuru\u015funda \u00f6nceki timeout'u temizle\n  return () => {\n    clearTimeout(handler);\n  };\n}, [inputValue, defaultSuggestions]); \/\/ inputValue veya defaultSuggestions de\u011fi\u015fti\u011finde \u00e7al\u0131\u015ft\u0131r<\/code><\/pre>\n<p>Bu <code>useEffect<\/code> hook&#8217;u, <code>inputValue<\/code> her de\u011fi\u015fti\u011finde 500 milisaniye bekler. E\u011fer bu s\u00fcre i\u00e7inde <code>inputValue<\/code> tekrar de\u011fi\u015firse, \u00f6nceki <code>setTimeout<\/code> temizlenir ve yeni bir tane ba\u015flat\u0131l\u0131r. Bu sayede, kullan\u0131c\u0131 h\u0131zl\u0131ca yazarken yaln\u0131zca son tu\u015f vuru\u015fundan sonraki 500ms&#8217;lik duraklamada API iste\u011fi g\u00f6nderilir.<\/p>\n<p><strong>Not:<\/strong> <code>onChange<\/code> fonksiyonundaki yerel filtreleme mant\u0131\u011f\u0131n\u0131 bu <code>useEffect<\/code> i\u00e7ine ta\u015f\u0131m\u0131\u015f olduk. <code>onChange<\/code> art\u0131k sadece <code>setInputValue<\/code> \u00e7a\u011f\u0131racak.<\/p>\n<pre><code class=\"language-jsx\">\/\/ G\u00fcncellenmi\u015f onChange fonksiyonu\nconst onChange = (e) => {\n  const userInput = e.target.value;\n  setInputValue(userInput);\n  setActiveSuggestionIndex(-1);\n  \/\/ setShowSuggestions(true); \/\/ Bu, useEffect i\u00e7inde y\u00f6netilecek\n};<\/code><\/pre>\n<h4>\u00d6nerileri G\u00f6r\u00fcnt\u00fcleme (<code><\/p>\n<ul><\/code>\/<code><\/p>\n<li><\/code>)<\/h4>\n<p>\u00d6neri listesi, <code>showSuggestions<\/code> ve <code>suggestions<\/code> dizisinin bo\u015f olup olmamas\u0131na ba\u011fl\u0131 olarak ko\u015fullu olarak render edilmelidir.<\/p>\n<pre><code class=\"language-jsx\">\/\/ Autocomplete.jsx i\u00e7inde, return ifadesinin i\u00e7inde, input'tan sonra\n{showSuggestions && (inputValue.length > 0 || loading) && (\n  <ul id=\"suggestions-list\" role=\"listbox\" className=\"autocomplete-suggestions\">\n    {loading ? (\n      <li className=\"autocomplete-loading\">Y\u00fckleniyor...<\/li>\n    ) : suggestions.length ? (\n      suggestions.map((suggestion, index) => (\n        <li\n          key={suggestion}\n          onClick={() => onClick(suggestion)}\n          onMouseEnter={() => setActiveSuggestionIndex(index)}\n          className={<code>autocomplete-suggestion-item ${\n            index === activeSuggestionIndex ? 'active' : ''\n          }<\/code>}\n          role=\"option\"\n          aria-selected={index === activeSuggestionIndex}\n          id={<code>suggestion-${index}<\/code>}\n        >\n          {\/<em> Arama terimini vurgulama <\/em>\/}\n          {highlightMatch(suggestion, inputValue)}\n        <\/li>\n      ))\n    ) : (\n      <li className=\"autocomplete-no-results\">Sonu\u00e7 bulunamad\u0131.<\/li>\n    )}\n  <\/ul>\n)}<\/code><\/pre>\n<p><code>onClick<\/code> olay y\u00f6neticisi, bir \u00f6neriye t\u0131kland\u0131\u011f\u0131nda ne olaca\u011f\u0131n\u0131 belirler:<\/p>\n<pre><code class=\"language-jsx\">\/\/ Autocomplete.jsx i\u00e7inde\nconst onClick = (suggestion) => {\n  setInputValue(suggestion);\n  setSuggestions([]);\n  setShowSuggestions(false);\n  setActiveSuggestionIndex(-1);\n  if (onSelect) {\n    onSelect(suggestion); \/\/ \u00dcst bile\u015fene se\u00e7imi bildir\n  }\n  inputRef.current.focus(); \/\/ Se\u00e7im sonras\u0131 input'a odaklan\n};<\/code><\/pre>\n<p><code>highlightMatch<\/code> fonksiyonu, kullan\u0131c\u0131n\u0131n arama terimini \u00f6neri i\u00e7inde vurgulamak i\u00e7in kullan\u0131l\u0131r:<\/p>\n<pre><code class=\"language-jsx\">const highlightMatch = (text, query) => {\n  if (!query) return text;\n  const parts = text.split(new RegExp(<code>(${query})<\/code>, 'gi'));\n  return (\n    <span>\n      {parts.map((part, index) =>\n        part.toLowerCase() === query.toLowerCase() ? (\n          <strong key={index}>{part}<\/strong>\n        ) : (\n          <span key={index}>{part}<\/span>\n        )\n      )}\n    <\/span>\n  );\n};<\/code><\/pre>\n<h4>Klavye Navigasyonu (<code>onKeyDown<\/code>)<\/h4>\n<p>Klavye navigasyonu, otomatik tamamlama bile\u015fenlerinin olmazsa olmaz\u0131d\u0131r. Kullan\u0131c\u0131lar\u0131n fare kullanmadan \u00f6neriler aras\u0131nda gezinmesini ve se\u00e7im yapmas\u0131n\u0131 sa\u011flar.<\/p>\n<pre><code class=\"language-jsx\">\/\/ Autocomplete.jsx i\u00e7inde\nconst onKeyDown = (e) => {\n  \/\/ \u00d6neri listesi g\u00f6r\u00fcn\u00fcr de\u011filse klavye navigasyonu yapma\n  if (!showSuggestions || suggestions.length === 0) {\n    return;\n  }\n\n  \/\/ A\u015fa\u011f\u0131 ok tu\u015fu\n  if (e.key === 'ArrowDown') {\n    e.preventDefault(); \/\/ \u0130mlecin hareket etmesini engelle\n    setActiveSuggestionIndex((prevIndex) =>\n      prevIndex < suggestions.length - 1 ? prevIndex + 1 : 0\n    );\n  }\n  \/\/ Yukar\u0131 ok tu\u015fu\n  else if (e.key === 'ArrowUp') {\n    e.preventDefault(); \/\/ \u0130mlecin hareket etmesini engelle\n    setActiveSuggestionIndex((prevIndex) =>\n      prevIndex > 0 ? prevIndex - 1 : suggestions.length - 1\n    );\n  }\n  \/\/ Enter tu\u015fu\n  else if (e.key === 'Enter') {\n    if (activeSuggestionIndex !== -1) {\n      e.preventDefault(); \/\/ Form submit etmesini engelle\n      onClick(suggestions[activeSuggestionIndex]);\n    } else {\n      \/\/ E\u011fer aktif \u00f6neri yoksa ve Enter'a bas\u0131ld\u0131ysa, mevcut input de\u011ferini kabul et\n      \/\/ veya bir arama tetikle\n      \/\/ setSuggestions([]);\n      \/\/ setShowSuggestions(false);\n      \/\/ console.log(\"Arama tetiklendi:\", inputValue);\n    }\n  }\n  \/\/ Escape tu\u015fu\n  else if (e.key === 'Escape') {\n    setShowSuggestions(false);\n    setActiveSuggestionIndex(-1);\n    setSuggestions([]);\n  }\n};<\/code><\/pre>\n<p>Bu <code>onKeyDown<\/code> y\u00f6neticisi, kullan\u0131c\u0131n\u0131n <code>ArrowDown<\/code>, <code>ArrowUp<\/code>, <code>Enter<\/code> ve <code>Escape<\/code> tu\u015flar\u0131na bast\u0131\u011f\u0131nda uygun eylemleri ger\u00e7ekle\u015ftirir. \u00d6zellikle <code>ArrowDown<\/code> ve <code>ArrowUp<\/code> tu\u015flar\u0131nda <code>e.preventDefault()<\/code> \u00e7a\u011fr\u0131s\u0131 yapmak, imlecin giri\u015f alan\u0131nda hareket etmesini engeller ve sadece \u00f6neri listesindeki se\u00e7imi de\u011fi\u015ftirir.<\/p>\n<h3>Kullan\u0131c\u0131 Deneyimini (UX) ve Eri\u015filebilirli\u011fi (Accessibility) Geli\u015ftirme<\/h3>\n<p>\u0130yi bir otomatik tamamlama bile\u015feni sadece \u00e7al\u0131\u015fmakla kalmaz, ayn\u0131 zamanda kullan\u0131c\u0131 dostu ve eri\u015filebilir olmal\u0131d\u0131r.<\/p>\n<h4>Eri\u015filebilirlik (ARIA Attributes)<\/h4>\n<p>Web i\u00e7eri\u011fi eri\u015filebilirlik y\u00f6nergeleri (WCAG) uyar\u0131nca, otomatik tamamlama bile\u015fenlerinin ekran okuyucular ve di\u011fer yard\u0131mc\u0131 teknolojilerle uyumlu olmas\u0131 \u00f6nemlidir. ARIA (Accessible Rich Internet Applications) \u00f6zelliklerini kullanarak bunu sa\u011flayabiliriz:<\/p>\n<p>*   <strong><code>aria-autocomplete=\"list\"<\/code>:<\/strong> Giri\u015f alan\u0131n\u0131n bir liste \u00f6nerileri sa\u011flad\u0131\u011f\u0131n\u0131 belirtir.<br \/>\n*   <strong><code>role=\"combobox\"<\/code>:<\/strong> Giri\u015f alan\u0131n\u0131 ve ili\u015fkili a\u00e7\u0131l\u0131r listeyi birle\u015fik bir kontrol olarak tan\u0131mlar.<br \/>\n*   <strong><code>aria-controls=\"suggestions-list\"<\/code>:<\/strong> Giri\u015f alan\u0131n\u0131n hangi elementin (\u00f6neri listesi) i\u00e7eri\u011fini kontrol etti\u011fini belirtir.<br \/>\n*   <strong><code>role=\"listbox\"<\/code>:<\/strong> \u00d6neri listesini bir liste kutusu olarak tan\u0131mlar.<br \/>\n*   <strong><code>role=\"option\"<\/code>:<\/strong> Her bir \u00f6neri \u00f6\u011fesini bir liste kutusu se\u00e7ene\u011fi olarak tan\u0131mlar.<br \/>\n*   <strong><code>aria-selected=\"true\/false\"<\/code>:<\/strong> Klavye ile aktif olan \u00f6nerinin se\u00e7ili oldu\u011funu belirtir.<br \/>\n*   <strong><code>id<\/code> ve <code>aria-activedescendant<\/code>:<\/strong> Giri\u015f alan\u0131n\u0131n, klavye ile gezinirken aktif olan \u00f6nerinin <code>id<\/code>&#8216;sini i\u015faret etmesini sa\u011flar. Bu, ekran okuyucular\u0131n aktif \u00f6\u011feyi do\u011fru bir \u015fekilde duyurmas\u0131n\u0131 sa\u011flar.<\/p>\n<p><code>Autocomplete.jsx<\/code> dosyam\u0131zda bu ARIA \u00f6zelliklerini zaten ekledik:<\/p>\n<pre><code class=\"language-jsx\">\/\/ input elementinde\n<input\n  \/\/ ... di\u011fer \u00f6zellikler ...\n  aria-autocomplete=\"list\"\n  aria-controls=\"suggestions-list\"\n  aria-activedescendant={activeSuggestionIndex !== -1 ? <code>suggestion-${activeSuggestionIndex}<\/code> : undefined}\n  className=\"autocomplete-input\"\n\/>\n\n\/\/ ul elementinde\n<ul id=\"suggestions-list\" role=\"listbox\" className=\"autocomplete-suggestions\">\n  {\/<em> ... <\/em>\/}\n  <li\n    \/\/ ... di\u011fer \u00f6zellikler ...\n    role=\"option\"\n    aria-selected={index === activeSuggestionIndex}\n    id={<code>suggestion-${index}<\/code>}\n  >\n    {\/<em> ... <\/em>\/}\n  <\/li>\n<\/ul><\/code><\/pre>\n<p><code>aria-activedescendant<\/code> \u00f6zelli\u011fini giri\u015f alan\u0131na dinamik olarak eklemeyi unutmay\u0131n. Bu, ekran okuyucular\u0131n klavye ile gezinirken hangi \u00f6nerinin vurguland\u0131\u011f\u0131n\u0131 anlamas\u0131na yard\u0131mc\u0131 olur.<\/p>\n<h4>Styling (CSS)<\/h4>\n<p>Bile\u015fenimizin g\u00f6r\u00fcn\u00fcm\u00fcn\u00fc iyile\u015ftirmek i\u00e7in basit CSS stilleri ekleyelim. <code>Autocomplete.css<\/code> dosyam\u0131z\u0131 olu\u015fturun:<\/p>\n<pre><code class=\"language-css\">\/<em> src\/components\/Autocomplete.css <\/em>\/\n.autocomplete-container {\n  position: relative;\n  width: 300px; \/<em> Geni\u015fli\u011fi ayarlayabilirsiniz <\/em>\/\n  margin: 20px auto;\n}\n\n.autocomplete-input {\n  width: 100%;\n  padding: 10px;\n  font-size: 16px;\n  border: 1px solid #ccc;\n  border-radius: 4px;\n  box-sizing: border-box; \/<em> Padding ve border geni\u015fli\u011fe dahil <\/em>\/\n}\n\n.autocomplete-suggestions {\n  position: absolute;\n  top: 100%; \/<em> Giri\u015f alan\u0131n\u0131n hemen alt\u0131na <\/em>\/\n  left: 0;\n  right: 0;\n  border: 1px solid #eee;\n  border-top: none;\n  background-color: #fff;\n  list-style: none;\n  padding: 0;\n  margin: 0;\n  max-height: 200px; \/<em> Maksimum y\u00fckseklik ve kayd\u0131rma <\/em>\/\n  overflow-y: auto;\n  z-index: 1000; \/<em> Di\u011fer elementlerin \u00fczerinde g\u00f6r\u00fcnmesini sa\u011fla <\/em>\/\n  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n  border-radius: 0 0 4px 4px;\n}\n\n.autocomplete-suggestion-item {\n  padding: 10px;\n  cursor: pointer;\n  border-bottom: 1px solid #f0f0f0;\n}\n\n.autocomplete-suggestion-item:last-child {\n  border-bottom: none;\n}\n\n.autocomplete-suggestion-item:hover,\n.autocomplete-suggestion-item.active {\n  background-color: #f0f0f0;\n}\n\n.autocomplete-suggestion-item strong {\n  font-weight: bold;\n  color: #007bff; \/<em> Vurgulanan metin rengi <\/em>\/\n}\n\n.autocomplete-no-results,\n.autocomplete-loading {\n  padding: 10px;\n  color: #666;\n  font-style: italic;\n  text-align: center;\n}<\/code><\/pre>\n<h3>Geli\u015fmi\u015f Konular ve Optimizasyonlar<\/h3>\n<p>\u015eimdiye kadar, sa\u011flam bir otomatik tamamlama bile\u015feni olu\u015fturduk. Ancak, daha da iyi hale getirmek i\u00e7in baz\u0131 geli\u015fmi\u015f konulara de\u011finelim.<\/p>\n<h4>Custom Hook Kullan\u0131m\u0131<\/h4>\n<p>Otomatik tamamlama mant\u0131\u011f\u0131n\u0131 daha mod\u00fcler hale getirmek ve ba\u015fka bile\u015fenlerde de kullanabilmek i\u00e7in \u00f6zel bir hook (custom hook) olu\u015fturabiliriz. Bu, bile\u015fenin karma\u015f\u0131kl\u0131\u011f\u0131n\u0131 azalt\u0131r ve kodu daha okunabilir hale getirir.<\/p>\n<pre><code class=\"language-jsx\">\/\/ src\/hooks\/useAutocomplete.js\nimport { useState, useEffect, useCallback } from 'react';\n\nconst useAutocomplete = (initialSuggestionsData, fetchSuggestionsApi, debounceDelay = 500) => {\n  const [inputValue, setInputValue] = useState('');\n  const [suggestions, setSuggestions] = useState([]);\n  const [showSuggestions, setShowSuggestions] = useState(false);\n  const [activeSuggestionIndex, setActiveSuggestionIndex] = useState(-1);\n  const [loading, setLoading] = useState(false);\n\n  \/\/ Veri kayna\u011f\u0131n\u0131 belirle\n  const sourceSuggestions = initialSuggestionsData || [];\n\n  \/\/ \u00d6neri getirme veya filtreleme fonksiyonu\n  const getSuggestions = useCallback(async (query) => {\n    if (query.length === 0) {\n      setSuggestions([]);\n      setShowSuggestions(false);\n      return;\n    }\n\n    setLoading(true);\n    try {\n      let result;\n      if (fetchSuggestionsApi) {\n        \/\/ API \u00e7a\u011fr\u0131s\u0131\n        result = await fetchSuggestionsApi(query);\n      } else {\n        \/\/ Yerel filtreleme\n        result = sourceSuggestions.filter(\n          (suggestion) =>\n            suggestion.toLowerCase().includes(query.toLowerCase())\n        );\n      }\n      setSuggestions(result);\n      setShowSuggestions(true);\n    } catch (error) {\n      console.error(\"\u00d6neriler getirilirken hata olu\u015ftu:\", error);\n      setSuggestions([]);\n      setShowSuggestions(false);\n    } finally {\n      setLoading(false);\n    }\n  }, [sourceSuggestions, fetchSuggestionsApi]);\n\n  \/\/ Debounce mekanizmas\u0131 i\u00e7in useEffect\n  useEffect(() => {\n    const handler = setTimeout(() => {\n      getSuggestions(inputValue);\n    }, debounceDelay);\n\n    return () => {\n      clearTimeout(handler);\n    };\n  }, [inputValue, debounceDelay, getSuggestions]);\n\n  const handleInputChange = (e) => {\n    setInputValue(e.target.value);\n    setActiveSuggestionIndex(-1);\n  };\n\n  const handleSelectSuggestion = (suggestion) => {\n    setInputValue(suggestion);\n    setSuggestions([]);\n    setShowSuggestions(false);\n    setActiveSuggestionIndex(-1);\n  };\n\n  const handleKeyDown = (e, suggestionsList) => {\n    if (!showSuggestions || suggestionsList.length === 0) {\n      return;\n    }\n\n    if (e.key === 'ArrowDown') {\n      e.preventDefault();\n      setActiveSuggestionIndex((prevIndex) =>\n        prevIndex < suggestionsList.length - 1 ? prevIndex + 1 : 0\n      );\n    } else if (e.key === 'ArrowUp') {\n      e.preventDefault();\n      setActiveSuggestionIndex((prevIndex) =>\n        prevIndex > 0 ? prevIndex - 1 : suggestionsList.length - 1\n      );\n    } else if (e.key === 'Enter') {\n      if (activeSuggestionIndex !== -1) {\n        e.preventDefault();\n        handleSelectSuggestion(suggestionsList[activeSuggestionIndex]);\n      }\n    } else if (e.key === 'Escape') {\n      setShowSuggestions(false);\n      setActiveSuggestionIndex(-1);\n      setSuggestions([]);\n    }\n  };\n\n  const handleBlur = () => {\n    setTimeout(() => {\n      setShowSuggestions(false);\n      setActiveSuggestionIndex(-1);\n    }, 100);\n  };\n\n  return {\n    inputValue,\n    suggestions,\n    showSuggestions,\n    activeSuggestionIndex,\n    loading,\n    handleInputChange,\n    handleSelectSuggestion,\n    handleKeyDown,\n    handleBlur,\n    setInputValue, \/\/ D\u0131\u015far\u0131dan input de\u011ferini manuel ayarlamak i\u00e7in\n  };\n};\n\nexport default useAutocomplete;<\/code><\/pre>\n<p>\u015eimdi <code>Autocomplete<\/code> bile\u015fenimiz bu hook&#8217;u kullanabilir:<\/p>\n<pre><code class=\"language-jsx\">\/\/ src\/components\/Autocomplete.jsx (useAutocomplete hook'u ile)\nimport React, { useRef } from 'react';\nimport useAutocomplete from '..\/hooks\/useAutocomplete';\nimport '.\/Autocomplete.css';\n\nconst Autocomplete = ({ suggestionsData, onSelect, fetchSuggestionsApi }) => {\n  const inputRef = useRef(null);\n\n  const {\n    inputValue,\n    suggestions,\n    showSuggestions,\n    activeSuggestionIndex,\n    loading,\n    handleInputChange,\n    handleSelectSuggestion,\n    handleKeyDown,\n    handleBlur,\n  } = useAutocomplete(suggestionsData, fetchSuggestionsApi);\n\n  const onClick = (suggestion) => {\n    handleSelectSuggestion(suggestion);\n    if (onSelect) {\n      onSelect(suggestion);\n    }\n    inputRef.current.focus();\n  };\n\n  const highlightMatch = (text, query) => {\n    if (!query) return text;\n    const parts = text.split(new RegExp(<code>(${query})<\/code>, 'gi'));\n    return (\n      <span>\n        {parts.map((part, index) =>\n          part.toLowerCase() === query.toLowerCase() ? (\n            <strong key={index}>{part}<\/strong>\n          ) : (\n            <span key={index}>{part}<\/span>\n          )\n        )}\n      <\/span>\n    );\n  };\n\n  return (\n    <div className=\"autocomplete-container\">\n      <input\n        type=\"text\"\n        ref={inputRef}\n        value={inputValue}\n        onChange={handleInputChange}\n        onKeyDown={(e) => handleKeyDown(e, suggestions)} \/\/ Hook'a suggestions listesini ge\u00e7irmeyi unutmay\u0131n\n        onFocus={() => setShowSuggestions(true)}\n        onBlur={handleBlur}\n        placeholder=\"Aramak istedi\u011finiz meyveyi yaz\u0131n...\"\n        aria-autocomplete=\"list\"\n        aria-controls=\"suggestions-list\"\n        aria-activedescendant={activeSuggestionIndex !== -1 ? <code>suggestion-${activeSuggestionIndex}<\/code> : undefined}\n        className=\"autocomplete-input\"\n      \/>\n\n      {showSuggestions && (inputValue.length > 0 || loading) && (\n        <ul id=\"suggestions-list\" role=\"listbox\" className=\"autocomplete-suggestions\">\n          {loading ? (\n            <li className=\"autocomplete-loading\">Y\u00fckleniyor...<\/li>\n          ) : suggestions.length ? (\n            suggestions.map((suggestion, index) => (\n              <li\n                key={suggestion}\n                onClick={() => onClick(suggestion)}\n                onMouseEnter={() => setActiveSuggestionIndex(index)}\n                className={<code>autocomplete-suggestion-item ${\n                  index === activeSuggestionIndex ? 'active' : ''\n                }<\/code>}\n                role=\"option\"\n                aria-selected={index === activeSuggestionIndex}\n                id={<code>suggestion-${index}<\/code>}\n              >\n                {highlightMatch(suggestion, inputValue)}\n              <\/li>\n            ))\n          ) : (\n            <li className=\"autocomplete-no-results\">Sonu\u00e7 bulunamad\u0131.<\/li>\n          )}\n        <\/ul>\n      )}\n    <\/div>\n  );\n};\n\nexport default Autocomplete;<\/code><\/pre>\n<p>Bu yap\u0131, <code>Autocomplete<\/code> bile\u015fenini sadece g\u00f6rsel sunumdan sorumlu hale getirirken, t\u00fcm mant\u0131\u011f\u0131 <code>useAutocomplete<\/code> hook&#8217;una ta\u015f\u0131r.<\/p>\n<h4>TypeScript Deste\u011fi<\/h4>\n<p>B\u00fcy\u00fck projelerde veya daha sa\u011flam kod yazmak istedi\u011finizde TypeScript kullanmak, bile\u015fenlerinizin ve hook&#8217;lar\u0131n\u0131z\u0131n tip g\u00fcvenli\u011fini sa\u011flaman\u0131za yard\u0131mc\u0131 olur.<\/p>\n<pre><code class=\"language-typescript\">\/\/ src\/types\/autocomplete.d.ts\nexport type AutocompleteSuggestion = string; \/\/ Veya { id: string; name: string; } gibi daha karma\u015f\u0131k bir obje\n\n\/\/ src\/hooks\/useAutocomplete.ts (\u00f6rnek tip tan\u0131mlamalar\u0131)\nimport { useState, useEffect, useCallback } from 'react';\n\ninterface UseAutocompleteProps {\n  initialSuggestionsData?: AutocompleteSuggestion[];\n  fetchSuggestionsApi?: (query: string) => Promise<AutocompleteSuggestion[]>;\n  debounceDelay?: number;\n}\n\ninterface UseAutocompleteReturn {\n  inputValue: string;\n  suggestions: AutocompleteSuggestion[];\n  showSuggestions: boolean;\n  activeSuggestionIndex: number;\n  loading: boolean;\n  handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n  handleSelectSuggestion: (suggestion: AutocompleteSuggestion) => void;\n  handleKeyDown: (e: React.KeyboardEvent<HTMLInputElement>, suggestionsList: AutocompleteSuggestion[]) => void;\n  handleBlur: () => void;\n  setInputValue: React.Dispatch<React.SetStateAction<string>>;\n  setShowSuggestions: React.Dispatch<React.SetStateAction<boolean>>; \/\/ D\u0131\u015far\u0131dan kontrol i\u00e7in\n  setActiveSuggestionIndex: React.Dispatch<React.SetStateAction<number>>; \/\/ D\u0131\u015far\u0131dan kontrol i\u00e7in\n}\n\nconst useAutocomplete = ({\n  initialSuggestionsData,\n  fetchSuggestionsApi,\n  debounceDelay = 500,\n}: UseAutocompleteProps): UseAutocompleteReturn => {\n  \/\/ ... (yukar\u0131daki useAutocomplete.js i\u00e7eri\u011fi, tiplerle birlikte)\n};\n\nexport default useAutocomplete;\n\n\/\/ src\/components\/Autocomplete.tsx\nimport React, { useRef } from 'react';\nimport useAutocomplete from '..\/hooks\/useAutocomplete';\nimport '.\/Autocomplete.css';\nimport { AutocompleteSuggestion } from '..\/types\/autocomplete';\n\ninterface AutocompleteProps {\n  suggestionsData?: AutocompleteSuggestion[];\n  onSelect?: (suggestion: AutocompleteSuggestion) => void;\n  fetchSuggestionsApi?: (query: string) => Promise<AutocompleteSuggestion[]>;\n}\n\nconst Autocomplete: React.FC<AutocompleteProps> = ({ suggestionsData, onSelect, fetchSuggestionsApi }) => {\n  \/\/ ... (yukar\u0131daki Autocomplete.jsx i\u00e7eri\u011fi, tiplerle birlikte)\n};\n\nexport default Autocomplete;<\/code><\/pre>\n<p>Bu, kodunuzu daha g\u00fcvenli, hata ay\u0131klamas\u0131 kolay ve bak\u0131m\u0131 yap\u0131labilir hale getirir.<\/p>\n<h4>Performans Optimizasyonlar\u0131 (<code>useCallback<\/code>, <code>useMemo<\/code>)<\/h4>\n<p><code>useCallback<\/code> ve <code>useMemo<\/code> hook&#8217;lar\u0131, fonksiyonlar\u0131n ve de\u011ferlerin gereksiz yere yeniden olu\u015fturulmas\u0131n\u0131 engelleyerek React bile\u015fenlerinin performans\u0131n\u0131 art\u0131rmaya yard\u0131mc\u0131 olur. <code>useAutocomplete<\/code> hook&#8217;umuzda <code>getSuggestions<\/code> fonksiyonu i\u00e7in <code>useCallback<\/code> kulland\u0131k. Bu, <code>getSuggestions<\/code> fonksiyonunun yaln\u0131zca ba\u011f\u0131ml\u0131l\u0131klar\u0131 de\u011fi\u015fti\u011finde yeniden olu\u015fturulmas\u0131n\u0131 sa\u011flar, b\u00f6ylece <code>useEffect<\/code> i\u00e7indeki <code>handler<\/code> fonksiyonunun gereksiz yere tekrar tekrar kurulmas\u0131n\u0131 \u00f6nler.<\/p>\n<p>Bu \u00f6zel durumda, <code>useAutocomplete<\/code> hook&#8217;unun i\u00e7inde <code>getSuggestions<\/code> i\u00e7in <code>useCallback<\/code> kullanmak, <code>useEffect<\/code>&#8216;in ba\u011f\u0131ml\u0131l\u0131k dizisindeki <code>getSuggestions<\/code> referans\u0131n\u0131n sabit kalmas\u0131n\u0131 sa\u011flar ve gereksiz <code>useEffect<\/code> tetiklemelerini \u00f6nler.<\/p>\n<h4>\u00dc\u00e7\u00fcnc\u00fc Taraf K\u00fct\u00fcphaneler<\/h4>\n<p>Karma\u015f\u0131k otomatik tamamlama senaryolar\u0131 (\u00f6rne\u011fin, \u00e7oklu se\u00e7im, gruplama, \u00f6zelle\u015ftirilmi\u015f renderlama) i\u00e7in s\u0131f\u0131rdan bir bile\u015fen olu\u015fturmak zaman al\u0131c\u0131 olabilir. Bu durumlarda, React Select, Downshift veya Autocomplete.js gibi pop\u00fcler \u00fc\u00e7\u00fcnc\u00fc taraf k\u00fct\u00fcphaneleri kullanmay\u0131 d\u00fc\u015f\u00fcnebilirsiniz. Bu k\u00fct\u00fcphaneler, bir\u00e7ok \u00f6zelli\u011fi ve eri\u015filebilirlik gereksinimini haz\u0131r olarak sunar ve geli\u015ftirme s\u00fcrecini h\u0131zland\u0131rabilir. Ancak, bu makalenin amac\u0131 kendi bile\u015feninizi nas\u0131l olu\u015fturaca\u011f\u0131n\u0131z\u0131 \u00f6\u011fretmek oldu\u011fu i\u00e7in, bu k\u00fct\u00fcphanelerin detaylar\u0131na girmedik.<\/p>\n<h3>Bile\u015feni Kullanma<\/h3>\n<p>Son olarak, <code>App.jsx<\/code> dosyam\u0131zda <code>Autocomplete<\/code> bile\u015fenimizi nas\u0131l kullanaca\u011f\u0131m\u0131z\u0131 g\u00f6relim.<\/p>\n<pre><code class=\"language-jsx\">\/\/ src\/App.jsx\nimport React from 'react';\nimport Autocomplete from '.\/components\/Autocomplete';\n\nconst App = () => {\n  const handleFruitSelect = (selectedFruit) => {\n    console.log('Se\u00e7ilen meyve:', selectedFruit);\n    \/\/ Burada se\u00e7ilen meyve ile ilgili ba\u015fka i\u015flemler yapabilirsiniz\n  };\n\n  \/\/ Yerel veri kayna\u011f\u0131\n  const fruits = [\n    'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry',\n    'Fig', 'Grape', 'Honeydew', 'Kiwi', 'Lemon',\n    'Mango', 'Nectarine', 'Orange', 'Papaya', 'Quince',\n    'Raspberry', 'Strawberry', 'Tangerine', 'Ugli Fruit', 'Vanilla Bean',\n    'Watermelon', 'Xigua', 'Yellow Passion Fruit', 'Zucchini'\n  ];\n\n  \/\/ API'den veri getirme fonksiyonu \u00f6rne\u011fi\n  const fetchCountries = async (query) => {\n    if (query.length < 2) return []; \/\/ En az 2 karakter girilince ara\n    const response = await fetch(<code>https:\/\/restcountries.com\/v3.1\/name\/${query}<\/code>);\n    const data = await response.json();\n    if (response.ok && Array.isArray(data)) {\n      return data.map(country => country.name.common);\n    }\n    return [];\n  };\n\n  return (\n    <div style={{ textAlign: 'center', marginTop: '50px' }}>\n      \n\n      <h2>Meyve Arama (Yerel Veri)<\/h2>\n      <Autocomplete\n        suggestionsData={fruits}\n        onSelect={handleFruitSelect}\n      \/>\n\n      <h2 style={{marginTop: '50px'}}>\u00dclke Arama (API Entegrasyonu)<\/h2>\n      <p>En az 2 karakter girin.<\/p>\n      <Autocomplete\n        fetchSuggestionsApi={fetchCountries}\n        onSelect={(selectedCountry) => console.log('Se\u00e7ilen \u00fclke:', selectedCountry)}\n      \/>\n    <\/div>\n  );\n};\n\nexport default App;<\/code><\/pre>\n<p>Bu \u00f6rnekte, ayn\u0131 <code>Autocomplete<\/code> bile\u015fenini hem yerel bir veri kayna\u011f\u0131yla (meyveler) hem de harici bir API ile (\u00fclkeler) kullanabiliyoruz. <code>fetchSuggestionsApi<\/code> prop&#8217;unu ge\u00e7irerek API entegrasyonunu devreye sokmu\u015f oluyoruz.<\/p>\n<h3>Sonu\u00e7<\/h3>\n<p>Bu makalede, React kullanarak s\u0131f\u0131rdan g\u00fc\u00e7l\u00fc, esnek ve eri\u015filebilir bir otomatik tamamlama bile\u015feni olu\u015fturman\u0131n t\u00fcm a\u015famalar\u0131n\u0131 detayl\u0131 bir \u015fekilde inceledik. Kullan\u0131c\u0131 giri\u015fini y\u00f6netmekten, veri filtrelemeye, klavye navigasyonuna, performans optimizasyonlar\u0131na ve eri\u015filebilirlik standartlar\u0131na uymaya kadar bir\u00e7ok \u00f6nemli konuyu ele ald\u0131k.<\/p>\n<p>Kendi otomatik tamamlama bile\u015feninizi olu\u015fturmak, React&#8217;in temel prensiplerini (durum y\u00f6netimi, ya\u015fam d\u00f6ng\u00fcs\u00fc hook&#8217;lar\u0131, olay y\u00f6netimi) derinlemesine anlaman\u0131za yard\u0131mc\u0131 olur ve size \u00f6zel ihtiya\u00e7lar\u0131n\u0131za g\u00f6re tamamen \u00f6zelle\u015ftirilebilir bir \u00e7\u00f6z\u00fcm sunar. Edindi\u011finiz bu bilgilerle, sadece otomatik tamamlama de\u011fil, ayn\u0131 zamanda di\u011fer karma\u015f\u0131k UI bile\u015fenlerini de benzer prensiplerle in\u015fa edebilirsiniz. Unutmay\u0131n, iyi bir kullan\u0131c\u0131 deneyimi ve eri\u015filebilirlik, her modern web uygulamas\u0131n\u0131n temelidir.<\/body><\/p>\n","protected":false},"excerpt":{"rendered":"React&#8217;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?\nOtomatik tamamlama (autocomplete) bile\u015fenleri, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmez","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[128],"tags":[],"class_list":{"0":"post-32449","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-react","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>React&#039;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"React&#039;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?\" \/>\n<meta property=\"og:description\" content=\"React&#039;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur? Otomatik tamamlama (autocomplete) bile\u015fenleri, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmez\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-21T20:41:06+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"React&#8217;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?\",\"datePublished\":\"2025-10-21T20:41:06+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/\"},\"wordCount\":1753,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"articleSection\":[\"React\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/\",\"name\":\"React'te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-10-21T20:41:06+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"React&#8217;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"React'te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/","og_locale":"tr_TR","og_type":"article","og_title":"React'te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?","og_description":"React'te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur? Otomatik tamamlama (autocomplete) bile\u015fenleri, modern web uygulamalar\u0131n\u0131n vazge\u00e7ilmez","og_url":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-10-21T20:41:06+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"17 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"React&#8217;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?","datePublished":"2025-10-21T20:41:06+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/"},"wordCount":1753,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"articleSection":["React"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/","url":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/","name":"React'te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-10-21T20:41:06+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/reactte-otomatik-tamamlama-bileseni-nasil-olusturulur\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"React&#8217;te Otomatik Tamamlama Bile\u015feni Nas\u0131l Olu\u015fturulur?"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/32449","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=32449"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/32449\/revisions"}],"predecessor-version":[{"id":32450,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/32449\/revisions\/32450"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=32449"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=32449"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=32449"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}