From 9fca4b262bbf984f1ee106341d5d28dbc23a2ca5 Mon Sep 17 00:00:00 2001 From: afds4567 <33995840+afds4567@users.noreply.github.com> Date: Sun, 14 Jan 2024 20:37:35 +0900 Subject: [PATCH 1/6] feat : Add HTTP client module --- frontend/src/api/http.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 frontend/src/api/http.ts diff --git a/frontend/src/api/http.ts b/frontend/src/api/http.ts new file mode 100644 index 00000000..3199c538 --- /dev/null +++ b/frontend/src/api/http.ts @@ -0,0 +1,35 @@ +import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; + +const API_POSTFIX = 'api'; +const BASE_URL = process.env.APP_URL || `https://mapbefine.com/${API_POSTFIX}`; + +const axiosInstance = axios.create({ + baseURL: BASE_URL, + headers: { + Authorization: `Bearer ${localStorage.getItem('userToken')}`, + }, +}); + +export interface HttpClient extends AxiosInstance { + get(url: string, config?: AxiosRequestConfig): Promise; + post( + url: string, + data?: any, + config?: AxiosRequestConfig, + ): Promise; + patch( + url: string, + data?: any, + config?: AxiosRequestConfig, + ): Promise; + put( + url: string, + data?: any, + config?: AxiosRequestConfig, + ): Promise; + delete(url: string, config?: AxiosRequestConfig): Promise; +} + +export const http: HttpClient = axiosInstance; + +http.interceptors.response.use((res) => res.data); From 0680e3421d209093ea8ac5f1ee22d9a4a655a5d3 Mon Sep 17 00:00:00 2001 From: afds4567 <33995840+afds4567@users.noreply.github.com> Date: Sun, 14 Jan 2024 20:52:43 +0900 Subject: [PATCH 2/6] feat : Add QueryClient and QueryClientProvider for React Query --- frontend/src/index.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index d2999a20..02f0ccae 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -1,3 +1,4 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import ReactDOM from 'react-dom/client'; import ReactGA from 'react-ga4'; import { ThemeProvider } from 'styled-components'; @@ -21,11 +22,15 @@ if (process.env.REACT_APP_GOOGLE_ANALYTICS) { ReactGA.initialize(process.env.REACT_APP_GOOGLE_ANALYTICS); } +const queryClient = new QueryClient(); + root.render( - - - - - - , + + + + + + + + , ); From d55c71c352e8f6c089157d79a2c81187e2c4ec4d Mon Sep 17 00:00:00 2001 From: afds4567 <33995840+afds4567@users.noreply.github.com> Date: Sun, 14 Jan 2024 22:37:05 +0900 Subject: [PATCH 3/6] feat : Add API and hook for fetching topics --- frontend/src/api/index.ts | 4 ++++ frontend/src/hooks/api/useTopicsQuery.ts | 13 +++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 frontend/src/api/index.ts create mode 100644 frontend/src/hooks/api/useTopicsQuery.ts diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts new file mode 100644 index 00000000..0f795191 --- /dev/null +++ b/frontend/src/api/index.ts @@ -0,0 +1,4 @@ +import { TopicCardProps } from '../types/Topic'; +import { http } from './http'; + +export const getTopics = (url: string) => http.get(url); diff --git a/frontend/src/hooks/api/useTopicsQuery.ts b/frontend/src/hooks/api/useTopicsQuery.ts new file mode 100644 index 00000000..df1b0232 --- /dev/null +++ b/frontend/src/hooks/api/useTopicsQuery.ts @@ -0,0 +1,13 @@ +import { useQuery } from '@tanstack/react-query'; + +import { getTopics } from '../../api'; + +const useTopicsQuery = (url: string) => { + const { data: topics } = useQuery({ + queryKey: ['topics', url], + queryFn: () => getTopics(url), + }); + return { topics }; +}; + +export default useTopicsQuery; From 13da28031d5a10924abe02b72c18473bb6762d1a Mon Sep 17 00:00:00 2001 From: afds4567 <33995840+afds4567@users.noreply.github.com> Date: Sun, 14 Jan 2024 22:37:20 +0900 Subject: [PATCH 4/6] refactor : Refactor authorization header in http.ts --- frontend/src/api/http.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/api/http.ts b/frontend/src/api/http.ts index 3199c538..da667bda 100644 --- a/frontend/src/api/http.ts +++ b/frontend/src/api/http.ts @@ -3,11 +3,11 @@ import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; const API_POSTFIX = 'api'; const BASE_URL = process.env.APP_URL || `https://mapbefine.com/${API_POSTFIX}`; +const token = localStorage.getItem('userToken'); + const axiosInstance = axios.create({ baseURL: BASE_URL, - headers: { - Authorization: `Bearer ${localStorage.getItem('userToken')}`, - }, + headers: token ? { Authorization: `Bearer ${token}` } : {}, }); export interface HttpClient extends AxiosInstance { From fed87190b4b3e6467d9e148272d488ab7aa4219c Mon Sep 17 00:00:00 2001 From: afds4567 <33995840+afds4567@users.noreply.github.com> Date: Sun, 14 Jan 2024 22:40:46 +0900 Subject: [PATCH 5/6] feat : Add useTopicsQuery hook to TopicCardContainer --- frontend/src/components/TopicCardContainer/index.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/TopicCardContainer/index.tsx b/frontend/src/components/TopicCardContainer/index.tsx index 3937fe70..5a7be846 100644 --- a/frontend/src/components/TopicCardContainer/index.tsx +++ b/frontend/src/components/TopicCardContainer/index.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react'; import { styled } from 'styled-components'; import useGet from '../../apiHooks/useGet'; +import useTopicsQuery from '../../hooks/api/useTopicsQuery'; import useKeyDown from '../../hooks/useKeyDown'; import { TopicCardProps } from '../../types/Topic'; import Box from '../common/Box'; @@ -25,7 +26,7 @@ function TopicCardContainer({ containerDescription, routeWhenSeeAll, }: TopicCardContainerProps) { - const [topics, setTopics] = useState(null); + const [_, setTopics] = useState(null); const { elementRef, onElementKeyDown } = useKeyDown(); const { fetchGet } = useGet(); @@ -38,10 +39,7 @@ function TopicCardContainer({ }, ); }; - - useEffect(() => { - setTopicsFromServer(); - }, []); + const { topics } = useTopicsQuery(url); return (
From 7036e7e8e0103db6e4c7077bb990ba2e52caae59 Mon Sep 17 00:00:00 2001 From: afds4567 <33995840+afds4567@users.noreply.github.com> Date: Sun, 14 Jan 2024 23:28:30 +0900 Subject: [PATCH 6/6] refactor : Refactor TopicCard and TopicCardContainer components eliminate useState,useEffect in TopicCardContainer --- frontend/src/components/TopicCard/index.tsx | 8 +++++--- .../components/TopicCardContainer/index.tsx | 19 ++----------------- frontend/src/hooks/api/useTopicsQuery.ts | 4 ++-- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/frontend/src/components/TopicCard/index.tsx b/frontend/src/components/TopicCard/index.tsx index 72aca615..9d50213f 100644 --- a/frontend/src/components/TopicCard/index.tsx +++ b/frontend/src/components/TopicCard/index.tsx @@ -1,4 +1,5 @@ -import { SyntheticEvent, useContext, useState } from 'react'; +import { QueryObserverResult, RefetchOptions } from '@tanstack/react-query'; +import { useContext, useState } from 'react'; import { styled } from 'styled-components'; import SeeTogetherSVG from '../../assets/seeTogetherBtn_filled.svg'; @@ -26,7 +27,9 @@ interface OnClickDesignatedProps { interface TopicCardExtendedProps extends TopicCardProps { cardType: 'default' | 'modal'; onClickDesignated?: ({ topicId, topicName }: OnClickDesignatedProps) => void; - getTopicsFromServer?: () => void; + getTopicsFromServer?: ( + options?: RefetchOptions | undefined, + ) => Promise>; } function TopicCard({ @@ -39,7 +42,6 @@ function TopicCard({ pinCount, bookmarkCount, isInAtlas, - isBookmarked, onClickDesignated, getTopicsFromServer, }: TopicCardExtendedProps) { diff --git a/frontend/src/components/TopicCardContainer/index.tsx b/frontend/src/components/TopicCardContainer/index.tsx index 5a7be846..48aa58f5 100644 --- a/frontend/src/components/TopicCardContainer/index.tsx +++ b/frontend/src/components/TopicCardContainer/index.tsx @@ -1,11 +1,8 @@ import { Swiper, Tab } from 'map-befine-swiper'; -import { useEffect, useState } from 'react'; import { styled } from 'styled-components'; -import useGet from '../../apiHooks/useGet'; import useTopicsQuery from '../../hooks/api/useTopicsQuery'; import useKeyDown from '../../hooks/useKeyDown'; -import { TopicCardProps } from '../../types/Topic'; import Box from '../common/Box'; import Flex from '../common/Flex'; import Space from '../common/Space'; @@ -26,20 +23,8 @@ function TopicCardContainer({ containerDescription, routeWhenSeeAll, }: TopicCardContainerProps) { - const [_, setTopics] = useState(null); + const { topics, refetchTopics } = useTopicsQuery(url); const { elementRef, onElementKeyDown } = useKeyDown(); - const { fetchGet } = useGet(); - - const setTopicsFromServer = async () => { - await fetchGet( - url, - '지도를 가져오는데 실패했습니다. 잠시 후 다시 시도해주세요.', - (response) => { - setTopics(response); - }, - ); - }; - const { topics } = useTopicsQuery(url); return (
@@ -110,7 +95,7 @@ function TopicCardContainer({ bookmarkCount={topic.bookmarkCount} isInAtlas={topic.isInAtlas} isBookmarked={topic.isBookmarked} - getTopicsFromServer={setTopicsFromServer} + getTopicsFromServer={refetchTopics} /> diff --git a/frontend/src/hooks/api/useTopicsQuery.ts b/frontend/src/hooks/api/useTopicsQuery.ts index df1b0232..bd871a28 100644 --- a/frontend/src/hooks/api/useTopicsQuery.ts +++ b/frontend/src/hooks/api/useTopicsQuery.ts @@ -3,11 +3,11 @@ import { useQuery } from '@tanstack/react-query'; import { getTopics } from '../../api'; const useTopicsQuery = (url: string) => { - const { data: topics } = useQuery({ + const { data: topics, refetch: refetchTopics } = useQuery({ queryKey: ['topics', url], queryFn: () => getTopics(url), }); - return { topics }; + return { topics, refetchTopics }; }; export default useTopicsQuery;