Issue 처리
디자인 회의 & 라우팅
멘토링 피드백
앞으로 참고할 사이트 정리
https://reactrouter.com/en/main/start/tutorial
https://tailwindcss.com/docs/width
https://assetstore.unity.com/ko
피드 페이지 제작
멘토님의 피드백을 듣고 기존 전역 상태관리 툴을 변경하기로 했다.
// map 에서 카테고리 분류하는 단계
// 1. client 부분 구현 완료
// 2. 어 근데 각각 map 에 맞게 어떻게 뿌려줌? (백엔드에서 map 관련해서는 명세서 정의 안된 상태)
// 3. 요청 보낼 때, map/:statusCode 가 맞게 들어오도록 백엔드에게 오더
{
statusCode: 0,
statusName: '힘',
categories: [
{
categoryCode: 0,
categoryName: '웨이트'
},
{
categoryCode: 1,
categoryName: '등산'
}
]
}
// 4. 그거에 맞게 라우팅 수정
// 5. mock 파일 만듬. 저건 statusCode: 0라 public에 0.json으로 만듬
// 6. 각각 0번부터 4번까지 5개 만듬
// 7. 각각 번호에 맞게 요청이 들어가도록 코드 수정
// 8. 상호작용 시, 화면으로 맞게 들어가는지 확인
후에 수행했던 작업
const { statusCode } = useParams();
console.log(statusCode);
/map/:statusCode
으로 라우팅 수정mock 데이터로 테스트
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import Backdrop from '../components/common/Backdrop';
import ModalFrame from '../components/common/ModalFrame';
import ServerList from '../components/map/ServerList';
import { icons } from '../utility/icon';
import axios from 'axios';
interface Category {
categoryCode: number;
categoryName: string;
}
interface JsonData {
statusCode: number;
statusName: string;
categories: Category[];
}
const MapPage = () => {
const [categoryList, setCategoryList] = useState<string[]>([]);
const [iconNumbers, setIconNumbers] = useState<number[]>([]);
const { statusCode } = useParams();
useEffect(() => {
const fetchCategoryData = async () => {
try {
const response = await axios.get<JsonData>(
`../../public/categoryList/${statusCode}.json`,
);
const jsonData = response.data;
const selectedCategoryCodes = jsonData.categories.map(
(category) => category.categoryCode % icons.length,
);
const selectedCategoryNames = getSelectedCategoryNames(
selectedCategoryCodes,
jsonData.categories,
);
console.log(selectedCategoryCodes);
console.log(selectedCategoryNames);
setCategoryList(selectedCategoryNames);
setIconNumbers(selectedCategoryCodes);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchCategoryData();
}, [statusCode]);
const getSelectedCategoryNames = (
selectedCategoryCodes: number[],
categories: Category[],
) => {
return selectedCategoryCodes
.filter((code) =>
categories.some((category) => category.categoryCode === code),
)
.map((code) => {
const selectedCategory = categories.find(
(category) => category.categoryCode === code,
);
return selectedCategory ? selectedCategory.categoryName : '';
});
};
return (
<div className="flex justify-center items-center w-full h-full absolute bg-map bg-center bg-cover">
<Backdrop>
<ModalFrame width={1020} height={680}>
<div className="w-[800px] h-[80px] flex justify-center items-center text-4xl mb-4">
Servers
</div>
<div className="w-full h-px bg-gray-600"></div>
<div className="w-[800px] h-[480px] flex flex-col justify-around items-center p-10 gap-4">
{categoryList.map((categoryName, index) => (
<ServerList
key={index}
title={categoryName}
categoryCode={iconNumbers[index]}
/>
))}
</div>
</ModalFrame>
</Backdrop>
</div>
);
};
export default MapPage;
// interface Category: 카테고리에 대한 정보를 담는 인터페이스입니다.
// interface JsonData: 서버로부터 받아온 JSON 데이터의 형식을 정의하는 인터페이스입니다.
// const MapPage: 맵 페이지 컴포넌트를 정의합니다.
// const [categoryList, setCategoryList]: 카테고리 이름 목록과 해당 이름들을 변경할 수 있는 함수를 저장하는 상태를 생성합니다.
// const [iconNumbers, setIconNumbers]: 카테고리 코드 목록과 해당 코드들을 변경할 수 있는 함수를 저장하는 상태를 생성합니다.
// const { statusCode } = useParams(): 현재 URL의 파라미터로부터 statusCode 값을 가져옵니다.
// useEffect: 컴포넌트가 렌더링된 이후에 실행되는 부분입니다.
// fetchCategoryData: 서버로부터 카테고리 데이터를 가져오는 함수입니다.
// const response = await axios.get<JsonData>(...): Axios를 사용하여 서버로부터 JSON 데이터를 가져옵니다.
// const selectedCategoryCodes = jsonData.categories.map(...): 카테고리 코드들을 배열로 만듭니다.
// const selectedCategoryNames = getSelectedCategoryNames(...): 카테고리 이름 목록을 가져옵니다.
// setCategoryList(selectedCategoryNames): 가져온 카테고리 이름 목록을 상태에 설정합니다.
// setIconNumbers(selectedCategoryCodes): 가져온 카테고리 코드 목록을 상태에 설정합니다.
// getSelectedCategoryNames: 선택된 카테고리 코드에 따른 이름 목록을 반환하는 함수입니다.
// return (...): 맵 페이지 컴포넌트의 UI를 정의합니다.
// {categoryList.map(...)}: 카테고리 목록을 순회하면서 ServerList 컴포넌트를 렌더링합니다.
// <ServerList ... />: 카테고리의 이름과 아이콘 코드를 ServerList 컴포넌트로 전달합니다.
1차 코드 리팩토링
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import Backdrop from '../components/common/Backdrop';
import ModalFrame from '../components/common/ModalFrame';
import ServerList from '../components/map/ServerList';
import axios from 'axios';
interface Category {
categoryCode: number;
categoryName: string;
}
interface JsonData {
statusCode: number;
statusName: string;
categories: Category[];
}
const MapPage = () => {
const [categoryList, setCategoryList] = useState<string[]>([]);
const [iconNumbers, setIconNumbers] = useState<number[]>([]);
const { statusCode } = useParams();
useEffect(() => {
const fetchCategoryData = async () => {
try {
const response = await axios.get<JsonData>(
`../../public/categoryList/${statusCode}.json`,
);
const jsonData = response.data;
setCategoryList(
jsonData.categories.map((category) => {
const { categoryName } = category;
return categoryName;
}),
);
setIconNumbers(
jsonData.categories.map((category) => {
const { categoryCode } = category;
return categoryCode;
}),
);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchCategoryData();
}, [statusCode]);
return (
<div className="flex justify-center items-center w-full h-full absolute bg-map bg-center bg-cover">
<Backdrop>
<ModalFrame width={1020} height={680}>
<div className="w-[800px] h-[80px] flex justify-center items-center text-4xl mb-4">
Servers
</div>
<div className="w-full h-px bg-gray-600"></div>
<div className="w-[800px] h-[480px] flex flex-col justify-around items-center p-10 gap-4">
{categoryList.map((categoryName, index) => (
<ServerList
key={index}
title={categoryName}
categoryCode={iconNumbers[index]}
/>
))}
</div>
</ModalFrame>
</Backdrop>
</div>
);
};
export default MapPage;
2차 코드 리팩토링
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import Backdrop from '../components/common/Backdrop';
import ModalFrame from '../components/common/ModalFrame';
import ServerList from '../components/map/ServerList';
import axios from 'axios';
interface Category {
categoryCode: number;
categoryName: string;
}
interface JsonData {
statusCode: number;
statusName: string;
categories: Category[];
}
const MapPage = () => {
const [categoryList, setCategoryList] = useState<string[]>([]);
const [iconNumbers, setIconNumbers] = useState<number[]>([]);
const { statusCode } = useParams();
useEffect(() => {
const fetchCategoryData = async () => {
try {
const response = await axios.get<JsonData>(
`../../public/categoryList/${statusCode}.json`,
);
const jsonData = response.data;
const codes: number[] = [];
const names: string[] = [];
jsonData.categories.forEach((category) => {
const { categoryCode, categoryName } = category;
codes.push(categoryCode);
names.push(categoryName);
});
setCategoryList(names);
setIconNumbers(codes);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchCategoryData();
}, [statusCode]);
return (
<div className="flex justify-center items-center w-full h-full absolute bg-map bg-center bg-cover">
<Backdrop>
<ModalFrame width={1020} height={680}>
<div className="w-[800px] h-[80px] flex justify-center items-center text-4xl mb-4">
Servers
</div>
<div className="w-full h-px bg-gray-600"></div>
<div className="w-[800px] h-[480px] flex flex-col justify-around items-center p-10 gap-4">
{categoryList.map((categoryName, index) => (
<ServerList
key={index}
title={categoryName}
categoryCode={iconNumbers[index]}
/>
))}
</div>
</ModalFrame>
</Backdrop>
</div>
);
};
export default MapPage;
메서드 forEach
를 사용하여 categoryCode
, categoryName
을 한 번에 담아 처리했다.
index를 꼭 전달해야 하는 이유
수료 후
Next.js, 스토리 북 테스트 코드 등등 기존 프로젝트 확장
Params(Category)에 따른 페이지 리팩토링
Feed 페이지 구현
❗️ 위 제목을 누를 시, 해당 깃허브 코드 링크로 이동합니다.
팀원 한 분이 util 코드들을 둘로 쪼개로 map으로 서로 연결되게 처리했는데
이 부분에서 타입스크립트를 왜 쓰는지 알겠더라..
FeedItem으로 props들을 다 넘겨주는 것이 아니라 feed 자체를 넘겨줘버리고
안에서 구조 분해 할당으로 푸는 것 중요
이 feed는 Feed로 타입 지정해놨었으므로 맞춰서 타입 지정만 해주면 간편
Main.tsx는 Feed들의 배열이고, FeedItem은 푼 상태로 전달받은 하나의 데이터이므로 그냥 Feed
검색 기능 추가
카테고리 별 페이지 이동 기능 추가
글 작성 기능 추가
무한 스크롤 기능 추가
유저 프로필 연결 & 클릭 시, 모달창 노출
좋아요 기능 추가
피드 상세 페이지 추가
초보 용사 스타터 팩 !
벌써 마무리라니.. 🥹
이제 우리 서비스를 코드스테이츠 모든 팀원들 앞에서 발표하는 시간이 되었다.
유튜버 경험을 살려 우리 팀원들의 기술 발표 영상을 편집하여 인코딩했다.
매우 많은 시련이 있었다..
1. 로그인 & 회원가입 페이지 | 2. 메인 페이지 |
---|---|
3. 스탯 & 맵 페이지 | 4. 피드 페이지 |
---|---|
5. 좋아요 & 댓글 | 6. 검색 기능 |
---|---|
허허.. 벌써 많은 시간이 흘렀다. 지금은 1월 11일이다.
그동안 자그마치 3개월이나 흘렀다.
해당 프로젝트 Stat & US은 8.28 ~ 9.19 동안 수행되었으니 말이다.
물론 그동안 놀았던 것은 절대 아니다.
나는 취업 준비에 바로 접어들었다.
취업 준비를 하면서 정말 시장이 매우 얼어있다는 것을 피부로 느꼈다.
매일 말로만 들었지 이 정도로 어려울 것이라곤 생각못했다.
몇 개월동안 준비하면서 코테를 준비해야 되나? 새로운 프로젝트를 해야되나?
정말 많은 생각들이 공존하면서도 이력서를 작성했고 면접은 계속 보러 다녔다.
덕분에 면접을 보면서 회사들이 실제로는 어떤 업무를 하고 있고
피드백을 받기도 하며, CS 등과 같은 지식이 정말 많이 늘었다.
계속 노마드코더를 보면서 Next.js & firebase를 공부했고, 현재도 하고 있다.
여전히 면접도 보러 다니고 있다. 모든 일은 역시 쉬운 것이 없다.
조금 여유가 남는대로 바로 이것저것 블로그에 작성하고 싶은 글이 많다.
그때까지 모두 화이팅이다. 넌 잘할 수 있고, 잘하고 있다 🔥