๐ Live Demo
๊ฒฝ๊ธฐ๋ ๋ฐ์ดํฐ ๋๋ฆผ์ ์ ๊ธฐ๋๋ฌผ ๋ณดํธ ํํฉ open api๋ฅผ ์ฌ์ฉํด ๊ฒฝ๊ธฐ๋ ์ง์ญ์ ์ ๊ธฐ ๋๋ฌผ์ ์๊ตฐ๊ตฌ, ๊ณต๊ณ ์ผ, ํ์ข ์ ๋ฐ๋ผ ์กฐํํ๊ณ ์ง๋ ์์์ ๊ฐ๊น์ด ๋ณดํธ์๋ฅผ ์ฐพ์ ์ ๊ธฐ ๋๋ฌผ ์ ์์ ๋๋ ์๋น์ค์ ๋๋ค.
- Skills: React,ย Reactย Router,ย SCSS
- Use: Postman,ย ๊ฒฝ๊ธฐ๋ ๋ฐ์ดํฐ ๋๋ฆผ ์ ๊ธฐ๋๋ฌผ ๋ณดํธ ํํฉ open api, ์นด์นด์ค๋งต api, axios
- Deploy: Netlify
๐ ๊ณต๊ณ ๊ธฐํ์ด ์ผ๋ง ๋จ์ง ์์ ์ ๊ธฐ๋๋ฌผ์ ๋ฐ์ํ ๋ฉํฐ ์ฌ๋ผ์ด๋๋ก ๋ณด์ฌ์ค๋๋ค.
๐ ๊ณต๊ณ ์ผ, ์๊ตฐ๊ตฌ, ํ์ข ์นดํ ๊ณ ๋ฆฌ์ ๋ง๋ ์ ๊ธฐ ๋๋ฌผ์ ์กฐํํ ์ ์์ต๋๋ค.
๐ ์นด์นด์ค๋งต ์์ ์ ๊ธฐ ๋๋ฌผ ๋ณดํธ์ ์์น๋ฅผ ํด๋ฆญํ๋ฉด ๋ณดํธ์ค์ธ ์ ๊ธฐ ๋๋ฌผ์ ๋ณด์ฌ์ค๋๋ค.
๐ ์ ๊ธฐ ๋๋ฌผ์ ์ด๋ฏธ์ง, ๊ตฌ์ฒด์ ์ธ ์ ๋ณด๋ฅผ ์ฌ์ฉ์๊ฐ ๋ณด๊ธฐ ์ฝ๊ฒ ํ ์ด๋ธ๋ก ๋ง๋ค์์ต๋๋ค.
๐ Context API๋ฅผ ํ์ฉํด ๋ค์ ๋ณด๊ณ ์ถ์ ๋๋ฌผ ๋ฐ์ดํฐ๋ฅผ ๊ธ๋ก๋ฒํ๊ฒ ๊ด๋ฆฌํด ์ด๋์๋ ์ ๋ฐ์ดํธ ํ ์ ์๊ฒ ๊ตฌํํ์ต๋๋ค.
โ ํฉ์ด์ ธ ์๋ ๋คํธ์ํฌ ํต์ ์ฝ๋๋ฅผ ํ ๊ณณ์ ๋ชจ์ ๊ด๋ฆฌํ์ต๋๋ค.
โ axios ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด fetch๋ณด๋ค ๊ฐ๋ ์ฑ ์ข๊ฒ ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์์ต๋๋ค.
โ ์นดํ ๊ณ ๋ฆฌ๊ฐ ๋ณ๊ฒฝ ๋ ๋๋ง๋ค ๊ฒ์ ์กฐ๊ฑด์ query state์ผ๋ก ๊ด๋ฆฌํด ์ปดํฌ๋ํธ์ ๋น์ฆ๋์ค ๋ก์ง์ ๊น๋ํ๊ฒ ๊ด๋ฆฌํ์ต๋๋ค.
// src/api/axios.js
// ์นดํ
๊ณ ๋ฆฌ ๊ฒ์์กฐ๊ฑด์ ๋ง๋ ์ ๊ธฐ๋๋ฌผ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ต๋๋ค.
export const getPets = async (query) => {
try {
const data = await axios
.get(
`${BASE_URL}&SIGUN_NM=${query.SIGUN_NM}&PBLANC_BEGIN_DE=${query.PBLANC_BEGIN_DE}&PBLANC_END_DE=${query.PBLANC_END_DE}&SPECIES_NM=${query.SPECIES_NM}`,
options
)
.then((res) =>
res.data.AbdmAnimalProtect ? res.data.AbdmAnimalProtect : []
);
return data; //๊ผญ ๋ฆฌํด ํด์ฃผ๊ธฐ
} catch (err) {
console.log(err.message);
}
// ์ง๋์์์ ์ ํํ ๋ณดํธ์์ ์ํ๊ฐ ๋ณดํธ์ค์ธ ์ ๊ธฐ๋๋ฌผ์ ๋ฐ์์ต๋๋ค.
export const getShelterPets = async (marker) => {
try {
const data = await axios
.get(`${BASE_URL}&SHTER_NM=${marker.Gb}&STATE_NM=๋ณดํธ์ค`)
.then((res) =>
res.data.AbdmAnimalProtect ? res.data.AbdmAnimalProtect : []
);
return data; //๊ผญ ๋ฆฌํด ํด์ฃผ๊ธฐ
} catch (err) {
console.log(err.message);
}
};
// src/page/Home.js
//...
useEffect(() => {
getPets(query).then((data) => {
setPets(data[1].row);
setCount(data[0].head[0].list_total_count);
});
}, [query]);
โ ์ด๋์๋ ๋ค์๋ณด๊ณ ์ถ์ ๋๋ฌผ์ ์ ๋ฐ์ดํธ ํ ์ ์๋๋ก context api๋ฅผ ์ฌ์ฉํด ๊ธ๋ก๋ฒํ๊ฒ ์ํ๋ฅผ ๊ด๋ฆฌํ์ต๋๋ค.
//src/ context/LikeContext.js
import { createContext, useContext, useEffect, useState } from "react";
const LikesContext = createContext();
// likes์๋ id๋ง ์ ์ฅํด์ include๋ก ํ๋จํ๊ณ , api์์ id๋ก ๋ฐ๋ก ๋ถ๋ฌ์ฌ ์ ์์ด์ pet๊น์ง ๋ก์ปฌ์ ์ ์ฅํจ
export function LikesProvider({ children }) {
const [likes, setLikes] = useState(readLikesFromLocal("likes"));
const [likeItems, setLikeItems] = useState(readLikesFromLocal("likeItems"));
const handleAdd = (id, pet) => {
setLikes({ ...likes, id });
setLikeItems([...likeItems, pet]);
};
const handleDelete = (id) => {
setLikes(likes.filter((item) => item !== id));
setLikeItems(likeItems.filter((item) => item.ABDM_IDNTFY_NO !== id));
};
// ์ฒ์ ๋ค์ด์์๋ ๋ก์ปฌ๋ก ๋ถํฐ ์ฝ๊ณ ๋์ ์ด๊ฑธ ๋ฐ๋ก ๋ก์ปฌ์ ๋ฃ์ด์ค์ผ ํ๋ค. ๊ทธ๋ฆฌ๊ณ set๋ ํด์ค์ผ ํ๋ค.
useEffect(() => {
localStorage.setItem("likes", JSON.stringify(likes));
localStorage.setItem("likeItems", JSON.stringify(likeItems));
setLikes(JSON.parse(localStorage.getItem("likes")));
setLikeItems(JSON.parse(localStorage.getItem("likeItems")));
}, []);
return (
<LikesContext.Provider
value={{ likes, likeItems, handleAdd, handleDelete }}
>
{children}
</LikesContext.Provider>
);
}
function readLikesFromLocal(key) {
const likes = localStorage.getItem(key);
return likes ? JSON.parse(likes) : [];
}
export const useLikes = () => useContext(LikesContext);
โ ํซ์นด๋์์ includes ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ์ฐํ ์ํ์ธ์ง ํ๋จํ์ต๋๋ค.
//src/ components/Like.
const { likes, handleAdd, handleDelete } = useLikes();
const [like, setLike] = useState(() => {
if (likes.includes(pet)) {
console.log("ํฌํจ");
return true;
} else {
console.log("์ํฌํจ");
return false;
}
});
const toggleLike = () => {
setLike((prev) => !prev);
if (like) {
handleDelete(pet);
} else {
handleAdd(pet);
}
};
useEffect(() => {
localStorage.setItem("likes", JSON.stringify(likes));
}, [likes]);
โ ์นด์นด์ค๋งต์ ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํด ๋ณดํธ์๋ฅผ ํด๋ฆญํ์ ๋ ๋ณดํธ์์ ๋ณดํธ์ค์ธ ๋๋ฌผ์ ๋ฐ์์์ต๋๋ค.
//src/page/Location.jsx
//...
kakao.maps.event.addListener(marker, "click", function () {
setShelter(marker.Gb);
getShelterPets(shelter).then((data) => {
setPets(data.length === 0 ? [] : data[1].row);
setCount(data.length === 0 ? "0" : data[0].head[0].list_total_count);
});
});
}
}, []);
- ๋ชจ๋ฐ์ผ์์ ๋ณผ๋ ํซ์นด๋๊ฐ ์๊ณก๋๋ ๊ฒ ํด๊ฒฐํ๊ธฐ
- ์นด์นด์ค๋งต ๊ธฐ๋ฅ์ ๋ ์ ํ์ฉํด ๋ณด๊ธฐ