Ö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"
}
]
Geliştirme Kodlarımız
BlogPost.jsx
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.css
.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);
}
index.css
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.
State Ekle
comments isminde bir state oluşturuyoruz. Bu state post için gelen Comment bilgilerini tutacak.
const [comments, setComments] = useState([]);
Post Bölümü Güncel Jsx Kodları
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>
Comments Bölümü JSX Kodları
<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>
loadComments Fonksiyonu
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
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.
Uygulama Test
Bu yazımızda böyleydi.
Bir sonraki yazımda görüşmek üzere.