Fetching Data
Şimdiye kadarki tüm örneklerde veri, component'in İÇİNDE (bir dizi ya da
nesne olarak) tanımlıydı. Gerçek uygulamalarda ise veri genellikle bir
sunucudan gelir. Bu ders, React'te bir sunucudan veri çekmenin (ve
oraya veri göndermenin) temel yolunu -- fetch fonksiyonunu -- anlatıyor.
fetch ile Veri Çekmek: GET
fetch, tarayıcının yerleşik bir fonksiyonudur -- bir URL'e HTTP isteği
atar ve bir Promise döner. Hooks dersinde gördüğümüz useEffect,
component ekrana geldiğinde bu isteği atmak için kullanılır:
import { useEffect, useState } from "react";
function BasicFetchGetExample() {
const [courses, setCourses] = useState([]);
// useEffect, component ekrana ilk geldiğinde (boş dependency array []) BİR
// KEZ çalışır -- veri çekmek için en yaygın kullanım budur. fetch(), bir
// Promise döner; .then() ile önce yanıtı JSON'a çeviriyoruz, sonra state'e
// yazıyoruz.
useEffect(() => {
fetch("/api/courses")
.then((response) => response.json())
.then((data) => setCourses(data));
}, []);
return (
<ul>
{courses.map((course) => (
<li key={course.id}>{course.name}</li>
))}
</ul>
);
}
useEffect'in ikinci argümanı boş bir dizi ([]) olduğu için, bu istek
yalnızca component İLK RENDER edildiğinde bir kez atılır.
fetch(url).then(...), önce yanıtı JSON'a çevirir, sonra gelen veriyi
setCourses ile state'e yazar -- state değişince React yeniden render
eder ve liste ekranda görünür.
Loading Durumu Göstermek
İstek atıldıktan sonra yanıt gelene kadar bir süre geçer -- bu sürede kullanıcıya boş bir ekran yerine bir şeyler olduğunu göstermek gerekir:
import { useEffect, useState } from "react";
function LoadingStateExample() {
const [courses, setCourses] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/courses")
.then((response) => response.json())
.then((data) => {
setCourses(data);
setLoading(false);
});
}, []);
// Veri gelene kadar ekranda bir "Loading..." mesajı göstermek, kullanıcıya
// bir şeylerin olduğunu bildirir -- boş bir liste yerine.
if (loading) {
return <p>Loading...</p>;
}
return (
<ul>
{courses.map((course) => (
<li key={course.id}>{course.name}</li>
))}
</ul>
);
}
loading state'i başlangıçta true; veri geldiğinde false'a
çekiyoruz. loading trueiken component <p>Loading...</p> render
edip ERKEN ÇIKIYOR (return) -- geri kalan JSX hiç render edilmiyor.
Hataları Yönetmek
Bir istek her zaman başarılı olmayabilir -- ağ kopabilir, sunucu hata dönebilir. Bunu yönetmezsek, kullanıcı sessizce boş bir ekranla kalır:
import { useEffect, useState } from "react";
function ErrorHandlingExample() {
const [courses, setCourses] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch("/api/courses")
.then((response) => {
if (!response.ok) {
// fetch(), 404/500 gibi HTTP hatalarında KENDİLİĞİNDEN reddetmez
// (reject) -- response.ok'u KONTROL ETMEK bize düşer.
throw new Error("Request failed: " + response.status);
}
return response.json();
})
.then((data) => setCourses(data))
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, []);
if (loading) {
return <p>Loading...</p>;
}
// error state doluysa, listeyi hiç render etmeden bir hata mesajı
// gösteriyoruz -- Conditional Rendering dersindeki if deseni.
if (error) {
return <p>Something went wrong: {error}</p>;
}
return (
<ul>
{courses.map((course) => (
<li key={course.id}>{course.name}</li>
))}
</ul>
);
}
response.ok, HTTP durum kodunun 200-299 aralığında olup olmadığını
söyler -- fetch, 404 ya da 500 gibi durumlarda KENDİLİĞİNDEN
reddetmediği (reject) için bunu elle kontrol edip throw etmemiz
gerekir. .catch(), bu hatayı yakalayıp error state'ine yazar;
.finally() ise başarılı ya da başarısız fark etmeksizin loading'i
kapatır.
Veri Göndermek: POST
Veri okumanın (GET) yanında, yeni bir kayıt oluşturmak için POST isteği atılır:
import { useState } from "react";
function PostRequestExample() {
const [name, setName] = useState("");
function handleSubmit(event) {
event.preventDefault();
// POST isteklerinde, gönderilecek veriyi `body`'ye JSON string olarak
// yazarız -- ve sunucuya bunun JSON olduğunu `Content-Type` header'ıyla
// bildiririz.
fetch("/api/courses", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name }),
});
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(event) => setName(event.target.value)}
placeholder="Course name"
/>
<button type="submit">Add</button>
</form>
);
}
POST isteğinde fetch'e ikinci bir argüman -- bir seçenekler nesnesi --
veririz: method: "POST", headers ile sunucuya gönderdiğimiz verinin
JSON olduğunu bildiriyoruz, body'ye de göndereceğimiz veriyi
JSON.stringify(...) ile bir metne çevirip koyuyoruz.
Güncellemek ve Silmek: PUT ve DELETE
Var olan bir kaydı güncellemek için PUT, silmek için DELETE kullanılır:
function PutAndDeleteExample({ courseId }) {
function handleRename(newName) {
// PUT, var olan bir kaydı TAMAMEN günceller -- yeni değeri gönderiyoruz,
// sunucu ilgili kaydı bununla değiştiriyor.
fetch(`/api/courses/${courseId}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: newName }),
});
}
function handleDelete() {
// DELETE, genellikle bir body göndermeden, yalnızca URL'deki id ile
// hangi kaydın silineceğini belirtir.
fetch(`/api/courses/${courseId}`, { method: "DELETE" });
}
return (
<div>
<button onClick={() => handleRename("Updated Name")}>Rename</button>
<button onClick={handleDelete}>Delete</button>
</div>
);
}
PUT, POST'a benzer şekilde bir body gönderir -- ama URL'de HANGİ
kaydın güncelleneceğini belirtir (/courses/${courseId}). DELETE ise
genellikle hiç body göndermeden, yalnızca URL'deki id ile hangi
kaydın silineceğini belirtir.
Özet ve Terimler Sözlüğü
fetch, bir URL'e HTTP isteği atıp bir Promise döner; useEffect ile
component ekrana geldiğinde çağrılır. GET veri okur, POST yeni kayıt
oluşturur, PUT var olan bir kaydı günceller, DELETE siler -- POST ve
PUT'ta body'ye JSON gönderilir. Bir istek her zaman loading ve
error state'leriyle birlikte yönetilmelidir -- kullanıcı, veri
gelene kadar bir bekleme mesajı, bir hata olduğunda da anlaşılır bir
mesaj görmelidir.
Terimler Sözlüğü
fetch — Tarayıcının, bir URL'e HTTP isteği atmak için kullanılan yerleşik fonksiyonu; bir Promise döner.
HTTP Metodu — Bir isteğin AMACINI belirten kelime: GET (okuma), POST (oluşturma), PUT (güncelleme), DELETE (silme).
Promise — Henüz tamamlanmamış, ileride bir sonuç (ya da hata) üretecek bir işlemi temsil eden JavaScript nesnesi.