prisma
์Next.js
๊ธฐ๋ฐ์ผ๋ก ์์ฑํ์ต๋๋ค.
Geolocation API
๋ฅผ ์ด์ฉํด์ ์ฌ์ฉ์๊ฐ ํ์ฉํ๋ฉด ํ์ฌ ๋๋ฐ์ด์ค์ ์๋/๊ฒฝ๋ ๊ฐ์ ์ป์ด๋
๋๋ค.
ํด๋น ์๋์ ๊ฒฝ๋๋ฅผ ๊ฒ์๊ธ ํ
์ด๋ธ์ ์ปฌ๋ผ์ ์ถ๊ฐํ๊ณ ๊ฒ์๊ธ์ ๋ถ๋ฌ์ฌ ๋ ์๋/๊ฒฝ๋, ์ฌ์ฉ์๊ฐ ์ ํํ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ์ฐํด์ ์ ํํ ๊ฑฐ๋ฆฌ๋ด๋ถ์ ์กด์ฌํ๋ ๊ฒ์๊ธ๋ง ๋ถ๋ฌ์ค๋๋ก ๋ง๋ค์์ต๋๋ค.
๋ง์ฝ ์ฌ์ฉ์๊ฐ ํ์ฉํ์ง ์์ ๊ฒฝ์ฐ์๋ ์์ฑํ๋ ๊ฒ์๊ธ์ด ์์น ๊ธฐ๋ฐ ๊ฒ์์์ ์ ์ธ๋๋๋ก ์ค๊ณํ์ต๋๋ค.
useCoords() hook ์ฐธ๊ณ
model Post {
# ์๋ ๋ ๊ฐ ์ถ๊ฐ
latitude Float?
longitude Float?
# ... ๋๋จธ์ง ์๋ต
}
์์ฒญ API ->
/api/posts?latitude&longitude&distance&page&offset
query string
์ ์ด์ฉํด์ ์๋, ๊ฒฝ๋, ๊ฑฐ๋ฆฌ, ํ์ด์ง, ๊ฐ์ ๊ฐ์ ์ ์กํฉ๋๋ค.
input[type="range"]
๋ฅผ ์ด์ฉํด์ 1~100KM๋ฅผ ์ ํํ๊ณ onChange()
์ด๋ฒคํธ๋ฅผ ์ด์ฉํด์ ๊ฐ์ด ๋ณ๊ฒฝํ๋ค๋ฉด ๋ค์ ๊ฒ์ํ๋๋ก ์์ฒญํฉ๋๋ค.
๋จ, ๋๋ฌด ๋ง์ ์์ฒญ์ด ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋๋ฐ์ด์ค๋ฅผ ์ ์ฉํด์ ์ฐ์์ ์ธ ์์ฒญ์ค ๊ฐ์ฅ ๋ง์ง๋ง ์์ฒญ๋ง ์ํํ๋๋ก ์ค๊ณํ์ต๋๋ค.
// 2022/04/13 - ๊ฒ์ํ ๊ฑฐ๋ฆฌ - by 1-blue
const [distance, setDistance] = useState(10);
// 2022/04/23 - ๋๋ฐ์ด์ฑ - by 1-blue
const [debounce, setDebounce] = useState(false);
// 2022/04/23 - timerId - by 1-blue
const timerId = useRef<any>(null);
// 2022/03/28 - ๊ฑฐ๋ฆฌ ์กฐ์ - by 1-blue
const onChangeDistance = useCallback(
(e: React.FormEvent<HTMLInputElement>) => {
if (!debounce) {
clearTimeout(timerId.current);
timerId.current = setTimeout(() => {
setDebounce(true);
}, 300);
}
setDistance(+e.currentTarget.value);
},
[debounce, setDebounce]
);
<input
type="range"
min={1}
value={distance}
onChange={onChangeDistance}
className="w-full py-4 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2 focus:rounded-md"
/>
// usePagination()์ useSWR()์ ์ปค์คํฐ๋ง์ด์งํ ๊ฒ์
// ์์์ input์ ๋ณ๊ฒฝํด์ "debounce"๊ฐ true๊ฐ ๋๋ ์๊ฐ ํ์ฌ ์ ์ฉํ ๊ฑฐ๋ฆฌ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ฒญํ๊ฒ ๋ฉ๋๋ค.
// 2022/04/13 - ๊ฒ์ ์กฐ๊ฑด์ ์ํด ๊ฒ์๋ ๊ฒ์๊ธ๋ค - by 1-blue
const [{ data: searchedPost, isValidating }, { page, setPage }, { offset }] =
usePagination<IPostResponse>(
+condition === SEARCH_CONDITION.AROUND &&
latitude &&
longitude &&
debounce
? `/api/posts?latitude=${latitude}&longitude=${longitude}&distance=${distance}`
: null,
{}
);
// ๋๋จธ์ง ์๋ตํ๊ณ ํต์ฌ ๋ก์ง๋ง ์ถ๊ฐํ์ต๋๋ค.
const page = +req.query.page - 1;
const offset = +req.query.offset;
let where = {};
// ์ธ๊ทผ ๊ฒ์๊ธ ๊ฒ์ ์ ์คํ
if (req.query.distance) {
// ๊ฑฐ๋ฆฌ, ์๋, ๊ฒฝ๋ ์ซ์๊ฐ์ผ๋ก ๊ฐ์ ธ์ค๊ธฐ
const distance = +req.query.distance;
const parsedLatitude = parseFloat(req.query.latitude.toString());
const parsedLongitue = parseFloat(req.query.longitude.toString());
// 1KM ๊ทผ์ฌ์น๊ฐ 0.008
// ๋ฐ๊ฒฝ "distance"KM ๋ด์์ ์์ฑํ ๊ฒ์๊ธ์ ๊ฒ์ํ๋ ์กฐ๊ฑด
where = {
latitude: {
gte: parsedLatitude - 0.008 * distance,
lte: parsedLatitude + 0.008 * distance,
},
longitude: {
gte: parsedLongitue - 0.008 * distance,
lte: parsedLongitue + 0.008 * distance,
},
};
}
// ์๋ ๋ถ๋ถ์ ๋์ค์ Promise.all()์ ์ด์ฉํด์ ๊ฐ์ ์ถ์ถํจ
const postsPromise = prisma.post.findMany({
take: offset,
skip: page * offset,
where,
include: {
user: {
select: {
name: true,
},
},
_count: {
select: {
answers: true,
recommendations: true,
},
},
},
orderBy: [
{
createdAt: "desc",
},
],
});
๋๋ฐ์ด์ค ๋ฏธ์ ์ฉ
๋๋ฐ์ด์ค ์ ์ฉ