TS 연습 프로젝트 23/06/12 ~ 23/06/18 후기
1. 개요
프로젝트를 진행한지 2주가 되었다. 그리고 지금까지 한 것들을 보니 이제 프로젝트를 슬슬 종료하고 다음 학습 목표를 진행해도 될 것 같다. 이 프로젝트의 주제는 자기 동네의 숨겨진, 대중들에게 잘 알려지지 않은 곳을 소개하는 것이었다. 그리고 이를 위해 꼭 구현해야 할 기능은 지역 CRUD, 회원 CRUD, 지도라 생각했다. 그리고 이제부터 이것들을 구현하기 위해 했던 것들과 느낌 등을 이야기할 것이다.
2. 기술 스택 소개
프로젝트를 진행하기 위해 이용했던 기술들과 이것들에 대한 나의 수준은 다음과 같다.
- Client
- TypeScript: JavaScript에서 정적 타입을 명시할 수 있는 언어이다. 진행했던 프로젝트의 규모가 작았기에 props 타입 지정 등은 혼자서 할 수 있었으며 Redux 등 타입을 잘 모르는 부분은 구글링을 통해 해결할 수 있다. 하지만 규모가 큰 프로젝트는 타입스크립트로 진행해본 적이 없기에 쉽지는 않을 것이라 생각한다.
- React: 프론트엔드 개발을 위한 라이브러리이다. 지금까지 진행했던 대부분의 프로젝트는 React로 진행했기에 작은 프로젝트라면 큰 어려움없이 다룰 수 있다고 생각한다.
- Redux: 상태 관리 라이브러리이다. Reducer, Action 등 상태 관리에 필요한 코드들을 작성하고 이용할 수 있다.
- Axios: HTTP 요청을 처리하는 라이브러리로 이를 통해 get, post, patch, put, delete 등의 요청을 할 수 있다.
- Styled-Components: CSS-in-JS 라이브러리로 컴포넌트들의 스타일링을 할 수 있고 styled components의 css를 이용하여 자주 이용하는 스타일을 분리하거나 props의 타입을 설정할 수 있다.
- Framer Motion: 애니메이션을 구현하기 위한 라이브러리로, 슬라이드, 컴포넌트의 크기 변경 등 간단한 애니메이션을 구현할 수 있다.
- React Hook Form: form은 관리하기 위한 라이브러리로 handleSubmit, register 등을 이용해 submit을 할 수 있으며, input을 따로 분리하였을 경우에도 submit 처리를 할 수 있다.
- Server
- Express: Node.js에서 웹 서버를 구축할 수 있게 하는 프레임워크로 작은 규모의 프로젝트에서 필요한 기능들을 구현할 수 있다.
- Multer: 파일 업로드를 처리할 수 있게 도와주는 미들웨어로, 이를 이용해 이미지를 처리할 수 있다.
3. 기억에 남는 것들
3-1. 카카오맵 API
코드스테이츠 메인 프로젝트를 진행했을 때, 다른 팀원이 카카오맵 API와 카카오페이 API를 이용했었다. 그래서 나도 실력 증진을 위해 이것들을 이용해봐야겠다고 생각했다. 그리고 이 프로젝트에서는 카카오맵 API를 이용했다. 프로젝트를 시작했을 때는 두려움이 컸었다. 왜냐하면 메인 프로젝트를 진행하면서 지도 관련해서 에러가 정말 많이 발생했었기 때문이다. 하지만 생각보다 어렵지 않아서 다행이었다. 이 프로젝트처럼 지도를 간단히 이용만 할 것이라면 공식 문서의 코드를 그대로 옮겨와도 크게 문제가 없기 때문이다. 다음은 본 프로젝트에서 카카오맵 API를 이용하는 부분이다.
import styled from "styled-components";
import React, { useEffect } from "react";
import { checkValidAddress } from "../../utils/functions";
interface IProps {
width: string;
height: string;
address?: string;
name?: string;
setShowMap?: React.Dispatch<React.SetStateAction<number>>;
}
const Map = styled.div<IProps>`
width: ${(props) => props.width};
height: ${(props) => props.height};
`;
export default function KakaoMap(props: IProps) {
useEffect(() => {
window.kakao.maps.load(() => {
const container = document.getElementById("map"); //지도를 담을 영역의 DOM 레퍼런스
const options = {
//지도를 생성할 때 필요한 기본 옵션
center: new window.kakao.maps.LatLng(33.450701, 126.570667), //지도의 중심좌표.
level: 3, //지도의 레벨(확대, 축소 정도)
};
const map = new window.kakao.maps.Map(container, options); //지도 생성 및 객체 리턴
// 주소-좌표 변환 객체를 생성
const geocoder = new window.kakao.maps.services.Geocoder();
// 주소로 좌표를 검색
geocoder.addressSearch(
props.address,
function (result: any, status: any) {
// 정상적으로 검색이 완료되었을 때
if (status === window.kakao.maps.services.Status.OK) {
const coords = new window.kakao.maps.LatLng(
result[0].y,
result[0].x
);
// 결과값으로 받은 위치를 마커로 표시
const marker = new window.kakao.maps.Marker({
map,
position: coords,
});
// 운포윈도우로 장소에 대한 설명 표시
const infowindow = new window.kakao.maps.InfoWindow({
content: `<div style="width:150px;text-align:center;padding:6px 0;">${props.name}</div>`,
});
infowindow.open(map, marker);
// 지도와 중심을 결과값으로 받은 위치로 이동
map.setCenter(coords);
} else {
// 정상적으로 주소강 입력되지 않았을 때
alert("주소가 잘못 입력되었습니다!");
if (props.setShowMap) {
props.setShowMap(0);
}
}
}
);
});
}, []);
return <Map id="map" width={props.width} height={props.height}></Map>;
}
위의 코드는 공식 문서의 코드와 크게 다르지 않다. 그리고 지오코더를 이용해 주소에서 위도/경도를 알아낸다. 주소가 올바를 경우는 상관이 없지만 올바르지 않을 경우, 위 코드의 status의 값이 "ZERO_RESULT" 등이 된다. 이를 이용해 주소가 올바르지 않을 경우의 행동을 지정해줄 수 있다.

3-2. props의 state를 변경하는 함수의 타입 정할 때
// Detail.tsx 중
const [showMap, setShowMap] = useState(0);
// 생략
<KakaoMap
width="100%"
height="100%"
address={data?.address}
name={data?.name}
setShowMap={setShowMap} // 함수 전달
/>
// KakaoMap.tsx 중
interface IProps {
width: string;
height: string;
address?: string;
name?: string;
setShowMap: () => void; // <= 이 부분에서 에러가 발생한다.
}
// 생략
export default function KakaoMap(props: IProps) {
// 생략
만약 위의 setShowMap과 같이 state의 상태를 갱신하는 함수를 props로 전달해야 할 때가 있다. 이 때, 위의 IProps처럼 setShowMap: () => void라고 하면 에러가 발생한다. 이 때, 다음과 같이 타입을 쉽게 알아낼 수 있다.

interface IProps {
width: string;
height: string;
address?: string;
name?: string;
setShowMap: React.Dispatch<React.SetStateAction<number>>;
}
setShowMap={setShowMap} 부분에 마우스를 올린 후 잠시 기다리면 위의 사진과 같이 타입을 확인할 수 있다. 이 타입을 복사한 후, 아래같이 작성해주면 된다.
3-3. Input을 분리한 후 react hook form을 이용하는 법
카카오맵과 더불어 가장 걱정했던 부분이다. 이 부분에서 대략 하루 정도의 시간이 소요되었던 것 같다. 간단히 얘기하자면 register대신 control을 이용했었다. 더 자세한 내용은 최하단의 링크를 통해 확인할 수 있다.
4. 소감 및 계획
처음으로 혼자서 진행했었던 타입스크립트 프로젝트였다. 그렇기에 비록 프로젝트 결과물의 질이 높다고는 할 수 없지만 뿌듯하다. 하지만 프로젝트를 배포를 해야 하는데 아직 배포 방법에 대해 정하지 못했다. 프론트엔드 코드는 메인 프로젝트에서 배포를 해보았기에 어떻게든 할 수 있지만 서버 코드는 어떻게 해야할지 잘 모르겠다. 일단 이 부분에 대해서는 조금 더 고민을 한 후 진행할 것이다.
그리고 아직 코드가 정리되어있지 않고 깃허브의 레포지토리에 README.md 파일이 없다. 그렇기에 틈틈이 코드를 정리하고 README.md를 추가할 예정이다. 그리고 Next.js를 공부할 것이다. 일단 인터넷 강의를 통해 Next.js를 공부한 후 조그마한 프로젝트를 한 번 더 하거나 CS/운영체제론 공부를 진행할 것이다.
- 프로젝트 깃허브: https://github.com/als982001/area_hunt
- 카카오맵 API 공식 문서: https://apis.map.kakao.com/
- react-hook-form에서 form과 input을 분리하는 법: https://jmjjjmj.tistory.com/128