
📗목차
지난 이미지 관련 데이터를 위한 서버 구현하기(7)에서 이미지 관련 데이터를 DB에 저장하고, 이미지 관련 데이터를 검색하는 API를 작성했다.
이번에는 프론트에서 이미지 관련 데이터를 검색하는 API를 호출해볼 것이다.
자, 생각해보는 시간을 가져보자.
이미지 관련 데이터를 빠르게 불러와야 화면이 빠르게 렌더링 된다.
빠른 렌더링을 위해서라면 비동기적인 작업 처리가 필요할 것이다.
그러므로 비동기적인 처리를 돕는 useEffect를 사용하여 API를 호출하겠다.
Axios를 사용하여 API 호출
const [imageData, setImageData] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { axios .get('http://localhost/Album/src/Data/GET_db.php') .then(res => { const data = res.data; const updatedImageData = []; for (let i in data) { if (data[i].title !== '') { updatedImageData.push({ "id": data[i].id, "title": data[i].title, "urlLeft": JSON.parse(data[i].urlLeft), "urlRight": JSON.parse(data[i].urlRight), "txt": JSON.parse(data[i].txt) }) } } setImageData(updatedImageData); setLoading(false); // 데이터 로딩이 완료됐음을 표시 }) .catch(error => { console.log(error); setLoading(false); // 데이터 로딩 실패 시도 표시 }); }, []);
이 코드를 작성하면서 생긴 에러가 있었다.
에러에 대해 해결하는 과정을 작성해보겠다.
위의 Axios를 사용하여 API 호출 코드를 보면 urlLeft, urlRight, txt만 JSON.parse()한 것을 볼 수 있다.
"urlLeft": JSON.parse(data[i].urlLeft),
"urlRight": JSON.parse(data[i].urlRight),
"txt": JSON.parse(data[i].txt)
처음에는 이 부분을 아래처럼 작성했었다.
"urlLeft": data[i].urlLeft,
"urlRight": data[i].urlRight,
"txt": data[i].txt
이대로 실행하면?
이런 에러가 뜬다.
Carousel 태그 안에 이미지 관련 데이터를 출력하는 부분에서 에러가 난 거 같다.
데이터가 제대로 불러와지지 않은 거 같다.
Carousel 태그 안의 이미지 데이터
{imageData.map(content => ( <div key={content.id} className="albumBox"> <div className="leftBox"> <h3>{content.title} 앨범집</h3> {content.urlLeft.map((url, urlIndex) => ( <img key={urlIndex} src={url} width={165} alt="이미지" /> ))} {content.txt.map((txt, txtIndex) => ( <span className="contents" key={txtIndex}>{txt}</span> ))} </div> <div className="rightBox"> <h3>추억을 열어 보세요.</h3> {content.urlRight.map((url, urlIndex) => ( <img key={urlIndex} src={url} width={165} alt="이미지" /> ))} <button className="entrance">펼쳐보기</button> </div> </div> ))}
에러 원인을 알아보자.
urlLeft, urlRight, txt 이 세 key들에 대한 값들이 배열 형태로 되어 있다.
[
{
"id": 1,
"title": "고양이",
"urlLeft": [
"images/cat/cat_pretty.jpg",
"images/cat/cat.jpg",
"images/cat/cat_closeup.jpg",
"images/cat/cat_box.jpg"
],
"urlRight": [
"images/cat/cat_sleep.jpg",
"images/cat/cat_stand.jpg"
],
"txt": [
"울 집 귀여운 고양이입니당.",
"이름은 호박이😻"
]
},
(...) // 생략
]
이렇게 아래처럼 값을 넣으면 배열 형태로 값이 들어가지 않는다.
"urlLeft": data[i].urlLeft,
"urlRight": data[i].urlRight,
"txt": data[i].txt
데이터는 문자열로 처리된다. 그래서 에러가 생긴 것이다.
"urlLeft": JSON.parse(data[i].urlLeft),
"urlRight": JSON.parse(data[i].urlRight),
"txt": JSON.parse(data[i].txt)
그럼 이제 Album 전체 코드를 보이겠다.
import React, { useState, useEffect, useCallback } from "react";
import { useNavigate } from 'react-router-dom';
import Carousel from "react-material-ui-carousel";
import '../style/Album.css';
const Album = () => {
const [darkMode, setDarkMode] = useState(false);
const [imageData, setImageData] = useState([]); // 이미지 관련 데이터 상태
const [loading, setLoading] = useState(true); // 데이터 로딩 상태
const navigate = useNavigate();
const onClick = () => setDarkMode(prev => !prev)
const handleLogout = useCallback(() => navigate('/'), [])
useEffect(() => {
axios
.get('http://localhost/Album/src/Data/GET_db.php')
.then(res => {
const data = res.data;
const updatedImageData = [];
for (let i in data) {
if (data[i].title !== '') {
updatedImageData.push({
"id": data[i].id,
"title": data[i].title,
"urlLeft": JSON.parse(data[i].urlLeft),
"urlRight": JSON.parse(data[i].urlRight),
"txt": JSON.parse(data[i].txt)
})
}
}
setImageData(updatedImageData);
setLoading(false); // 데이터 로딩이 완료됐음을 표시
})
.catch(error => {
console.log(error);
setLoading(false); // 데이터 로딩 실패 시도 표시
});
}, []);
return (
<div className={darkMode === true ? "dark" : "light"}>
<img
src={darkMode === true ? "images/light.png" : "images/dark.png"}
className="icon"
width="40"
onClick={onClick}
alt="Icon"
/>
<button className='exit' onClick={handleLogout}>로그아웃</button>
<Carousel
className="crsl"
autoPlay={false}
>
{imageData.map(content => (
<div key={content.id} className="albumBox">
<div className="leftBox">
<h3>{content.title} 앨범집</h3>
{content.urlLeft.map((url, urlIndex) => (
<img key={urlIndex} src={url} width={165} alt="이미지" />
))}
{content.txt.map((txt, txtIndex) => (
<span className="contents" key={txtIndex}>{txt}</span>
))}
</div>
<div className="rightBox">
<h3>추억을 열어 보세요.</h3>
{content.urlRight.map((url, urlIndex) => (
<img key={urlIndex} src={url} width={165} alt="이미지" />
))}
<button className="entrance">펼쳐보기</button>
</div>
</div>
))}
</Carousel>
</div>
);
};
export default Album;
아직 loading이라는 상태 변수를 선언하고서 사용하지 않았다.
다음 포스팅에서는 데이터 로딩 중일 때 표시되는 화면을 구현해볼 것이다.