
지난 시간에 이어 북스토어 프로젝트를 계속 진행해 보겠습니다.
이번 시간에는 전역 상태 관리를 통한 로그인 구현과 메인 화면의 도서 목록 UI 구성 과정을 정리합니다.
Zustand는 Redux와 같은 전역 상태 관리 라이브러리입니다.
Redux와 목적은 동일하지만, 훨씬 간결한 문법과 쉬운 사용성을 제공하는 것이 특징입니다.
이번 프로젝트에서는 다음과 같은 방식으로 상태를 관리했습니다.
이러한 구조를 통해 컴포넌트 간 상태 전달 없이도 로그인 상태를 쉽게 공유할 수 있습니다.
Axios를 활용하여 서버와 통신할 때,
HTTP 헤더의 Authorization에 토큰을 포함하도록 설정했습니다.
import axios, { AxiosRequestConfig } from "axios";
const axiosInstance = axios.create({
baseURL: BASE_URL,
timeout: DEFAULT_TIMEOUT,
headers: {
"content-type": "application/json",
Authorization: getToken() ? getToken() : "",
},
withCredentials: true,
...config,
});
위 설정을 통해 모든 요청에 자동으로 토큰이 포함되며,
별도의 처리 없이 인증이 필요한 API를 사용할 수 있습니다.
Axios의 인터셉터(Interceptor) 기능을 활용하여
API 응답에 대한 공통 처리를 구현했습니다.
특히, 인증 실패(401) 상황을 다음과 같이 처리했습니다.
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response.status === 401) {
removeToken();
window.location.href = "/login";
return;
}
return Promise.reject(error);
}
);
해당 로직을 통해:
즉, 사용자 인증 흐름을 일관되게 유지할 수 있습니다.
쿼리 스트링을 활용하면 다음과 같은 장점을 얻을 수 있습니다.
리액트에서는 다음과 같은 방법으로 쿼리 스트링을 다룹니다.
현재 URL 정보를 확인할 수 있는 훅입니다.
import { useLocation } from "react-router-dom";
const location = useLocation();
console.log(location);
쿼리 스트링을 상태처럼 관리할 수 있는 훅입니다.
import { useSearchParams } from "react-router-dom";
const [searchParams, setSearchParams] = useSearchParams();
const handleSwitch = (value: ViewMode) => {
const newSearchParams = new URLSearchParams(searchParams);
newSearchParams.set(QUERYSTRING.VIEW, value);
setSearchParams(newSearchParams);
};
이 방법을 사용하면 URL을 직접 조작하지 않고도
리액트 상태처럼 쿼리 스트링을 제어할 수 있습니다.
TypeScript에서 제공하는 Pick 유틸리티 타입은
기존 타입에서 필요한 속성만 선택하여 새로운 타입을 만들 때 사용합니다.
interface User {
id: number;
email: string;
age: number;
}
// 일부 속성만 선택
type UserPreview = Pick<User, "id" | "email">;
이 방식은 불필요한 데이터 노출을 줄이고,
명확한 타입 구조를 유지하는 데 유용합니다