Önemli: Diğer yazılarımla direkt bağlantılı bir yazıdır. İlk olarak bu yazıdan okumaya başladıysanız, eğitim serisine kısaca bir göz atmanızı tavsiye ederim.
Merhabalar.
Get isteği ile işlemlerimize devam ediyoruz.
Bu yazımda sorguladığımız API endpoint’ine query params ile veri gönderip data alma işlemini yapacağız.
BlogPost uygulamamıza bu yazımız için bir comment bölümü oluşturacağız. Her blog post’un altına Load Comments isimli bir buton ekleyeceğiz. Sonrasında ilgili postid’nin comment’lerini çekeceğiz.
Bunu yaparken jsonplaceholder’ın bize sunduğu query parameters kullanarak data çekmeyi göreceğiz.
İstediğimiz post’u çekebilmek için jsonplaceholder bize aşağıdaki gibi bir endpoint veriyor. Biz de buna istek atacağız.
Burada ?postId= kısmından sonra gelen 1 değeri dinamik olacak. O yüzden dinamik olarak buradaki veriyi parametre ile göndereceğiz. Bunu zaten geçen yazımda anlatmıştım.
https://jsonplaceholder.typicode.com/comments?postId=1 Buraya istek attığımızda elimize gelen data şu şekilde.
[
{
"postId": 1,
"id": 1,
"name": "id labore ex et quam laborum",
"email": "Eliseo@gardner.biz",
"body": "laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium"
},
{
"postId": 1,
"id": 2,
"name": "quo vero reiciendis velit similique earum",
"email": "Jayne_Kuhic@sydney.com",
"body": "est natus enim nihil est dolore omnis voluptatem numquam\net omnis occaecati quod ullam at\nvoluptatem error expedita pariatur\nnihil sint nostrum voluptatem reiciendis et"
},
{
"postId": 1,
"id": 3,
"name": "odio adipisci rerum aut animi",
"email": "Nikita@garfield.biz",
"body": "quia molestiae reprehenderit quasi aspernatur\naut expedita occaecati aliquam eveniet laudantium\nomnis quibusdam delectus saepe quia accusamus maiores nam est\ncum et ducimus et vero voluptates excepturi deleniti ratione"
},
{
"postId": 1,
"id": 4,
"name": "alias odio sit",
"email": "Lew@alysha.tv",
"body": "non et atque\noccaecati deserunt quas accusantium unde odit nobis qui voluptatem\nquia voluptas consequuntur itaque dolor\net qui rerum deleniti ut occaecati"
},
{
"postId": 1,
"id": 5,
"name": "vero eaque aliquid doloribus et culpa",
"email": "Hayden@althea.biz",
"body": "harum non quasi et ratione\ntempore iure ex voluptates in ratione\nharum architecto fugit inventore cupiditate\nvoluptates magni quo et"
}
]
import React, { useState } from 'react'
import './BlogPost.css'
import loadingGif from "../../Assets/Images/loading.gif"
const BlogPost = () => {
const [posts, setPosts] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [isData, setIsData] = useState(false);
const [isError, setIsError] = useState(null);
const [showError, setShowError] = useState(false);
const [searchId, setSearchId] = useState('');
const [comments, setComments] = useState([]);
const loadPosts = async () => {
try {
setComments([]);
setIsLoading(true);
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (response.ok) {
const data = await response.json();
setPosts(data);
setIsLoading(false);
if (data.length === 0 ? setIsData(false) : setIsData(true));
openMessageModal(`${data.length} posts found`);
} else {
setIsLoading(false);
setIsData(false);
openMessageModal('There was an error!');
}
} catch (error) {
setIsData(false);
openMessageModal('There was an error!');
}
};
const loadComments = async (id) => {
try {
setIsLoading(true);
const response = await fetch(`https://jsonplaceholder.typicode.com/comments?postId=${id}`);
if (response.ok) {
const data = await response.json();
setComments(data);
setIsLoading(false);
if (data.length === 0 ? setIsData(false) : setIsData(true));
openMessageModal(`${data.length} comments found`);
} else {
setIsLoading(false);
setIsData(false);
openMessageModal('There was an error!');
}
} catch (error) {
setIsData(false);
openMessageModal('There was an error!');
}
};
const openMessageModal = (info) => {
setIsError(info);
setShowError(true);
setTimeout(() => setShowError(false), 5000);
};
const getSearchById = async () => {
try {
setComments([]);
if (searchId === '') {
loadPosts();
}
else {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${searchId}`);
if (response.ok) {
const data = await response.json();
setPosts([data]);
setIsLoading(false);
if (data.length === 0 ? setIsData(false) : setIsData(true));
if ([data].length === 0) {
openMessageModal('Data not found');
}
openMessageModal(`${[data].length} posts found`);
} else {
setPosts([]);
openMessageModal('Data not found');
}
}
} catch (error) {
console.error('There was an error!', error);
}
}
const handleSearch = (e) => {
if (e.target.value === '') {
loadPosts();
}
setSearchId(parseInt(e.target.value));
}
return (
<div className="blogPost">
{showError && <div className="error">{isError}</div>}
<div className='search'>
<input type="number" name="searchId" value={searchId} onChange={handleSearch} placeholder="Search by ID" />
<button type='button' onClick={getSearchById}>Search</button>
<button onClick={loadPosts}>Load Posts</button>
</div>
{isLoading &&
<div className="center">
<img src={loadingGif} width={100} alt="Loading" />
</div>
}
{!isData &&
<div className="center">
<h3>There is no data</h3>
</div>
}
{isData &&
<div className="post-container">
<div className='posts'>
<h2>Posts</h2>
{isData &&
posts.map((post) => (
<div key={post.id} className="post">
<h2>{post.title}</h2>
<p>{post.body}</p>
<button onClick={() => loadComments(post.id)}>Load Comments</button>
</div>
))
}
</div>
<div className='comments'>
<h2>Comments</h2>
{
comments.map((comment) => (
<div key={comment.id} className="comment">
<h3>{comment.name}</h3>
<p>{comment.body}</p>
<p>{comment.email}</p>
</div>
))
}
</div>
</div>
}
</div>
);
}
export default BlogPost
.blogPost {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
button {
padding: 10px 20px;
margin: 20px 0;
border: none;
border-radius: 5px;
background-color: #007BFF;
color: white;
cursor: pointer;
}
.center {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
color: #ffffff;
}
.error {
width: 300px;
height: 50px;
border-radius: 20px;
position: fixed;
top: 20px;
right: 20px;
padding: 10px;
background-color: rgb(255, 0, 0);
color: white;
display: flex;
font-size: 15px;
font-weight: bold;
justify-content: center;
align-items: center;
z-index: 100;
}
.search {
margin-top: 20px;
display: flex;
direction: column;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 10px;
border: 1px solid #ccc;
border-radius: 20px;
width: 50%;
}
.search input {
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
flex-grow: 1;
margin-right: 10px;
}
.search input, .search button {
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
.search button {
padding: 10px;
border: none;
background-color: #007BFF;
color: white;
cursor: pointer;
flex-basis: 10%;
margin-right: 5px;
}
.search button:hover {
background-color: #0056b3;
}
.post-container {
display: flex;
direction: column;
justify-content: space-between;
flex-wrap: wrap;
border-radius: 20px;
}
.posts {
flex-basis: 70%;
color: #ffffff;
padding: 20px;
}
.post button{
position:absolute;
bottom: -10px;
right: 10px;
padding: 4px;
}
.post button:hover{
background-color: cadetblue;
}
.post {
position: relative;
border: 1px solid #ccc;
border-radius: 5px;
padding: 20px;
margin-top: 20px;
position: relative;
background-color: #ffffff;
color: rgb(45, 71, 187);
box-shadow: 0 0 10px rgba(114, 109, 109, 0.5);
}
.comments {
flex-basis: 25%;
width: 200px;
color: rgb(255, 255, 255);
margin-top: 20px;
}
.comment{
border: 1px solid #ccc;
border-radius: 5px;
padding: 20px;
margin-top: 20px;
position: relative;
background-color: #ffffff;
color: rgb(45, 71, 187);
box-shadow: 0 0 10px rgba(114, 109, 109, 0.5);
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: rgb(64,59,145);
background: radial-gradient(circle, rgba(64,59,145,1) 0%, rgba(38,38,167,1) 35%, rgba(71,79,214,1) 100%);
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
Görüntümüz günün sonunda şu şekilde olacak.
comments isminde bir state oluşturuyoruz. Bu state post için gelen Comment bilgilerini tutacak.
const [comments, setComments] = useState([]);
Eklediğimiz Load Comments butonu burada. Tıklandığında onClick event’i tetiklenecek. Bunu da loadComments fonksiyonuna bağladık.
<div className='posts'>
<h2>Posts</h2>
{isData &&
posts.map((post) => (
<div key={post.id} className="post">
<h2>{post.title}</h2>
<p>{post.body}</p>
<button onClick={() => loadComments(post.id)}>Load Comments</button>
</div>
))
}
</div>
<div className='comments'>
<h2>Comments</h2>
{
comments.map((comment) => (
<div key={comment.id} className="comment">
<h3>{comment.name}</h3>
<p>{comment.body}</p>
<p>{comment.email}</p>
</div>
))
}
</div>
const loadComments = async (id) => {
try {
setIsLoading(true);
const response = await fetch(`https://jsonplaceholder.typicode.com/comments?postId=${id}`);
if (response.ok) {
const data = await response.json();
setComments(data);
setIsLoading(false);
if (data.length === 0 ? setIsData(false) : setIsData(true));
openMessageModal(`${data.length} comments found`);
} else {
setIsLoading(false);
setIsData(false);
openMessageModal('There was an error!');
}
} catch (error) {
setIsData(false);
openMessageModal('There was an error!');
}
};
Query Params endpoint’leri aşağıdaki gibi göndeririz. ? işaretinden sonra değişken ismi = değer şeklindedir. Eğer birden fazla params kullanacaksak her params arasına & işareti koyarız.
const response = await fetch(`https://jsonplaceholder.typicode.com/comments?postId=${id}`);
Geri kalan kodlarımızın açıklamalarını diğer yazılarımdan biliyorsunuz. Anlamadığınız kısımlar için eski yazılarıma göz atınız.
Bu yazımızda böyleydi.
Bir sonraki yazımda görüşmek üzere.
Selamlar, bu yazımda Oly'nin 1 hafta boyunca olduğu GS iğnesi, yaşanan değişimleri anlatmaya çalışacağım. PCR…
Selamlar, bu yazımda Hemogram ve Biyokimya sonuçlarımızı göstermek için İÜCHH'ne tekrar gidişimizi ve sonrasını anlatacağım.…
Selamlar, bu yazımda GS iğnesine başlama kararımızı ve Oly’de bu süreçte nelere dikkat ediyor, neler…
Selamlar, bu yazımda İÜCHH'deki tedavi sürecimiz ve sonrasında yaşananlardan bahsetmeye çalışacağım. 20.06.2025 Cuma günü saat…
Eve Dönüş ve İlk Şüpheler 18 Haziran Perşembe saat 23 sularında İstanbul’daki evimize giriş yaptık.…
9 Haziran Pazartesi günü Aydın’daki sürecimiz bitti ve Antalya yolculuğumuz başladı. Saat 11 gibi yola…