본문 바로가기
항해99/프로젝트

[WIL-031] 클론 프로젝트 - Out Stagram 인스타그램 클론코딩

by junvely 2023. 5. 28.

Week목표 : 05/13일~05/18일 클론 프로젝트 Out Stagram : 인스타그램 클론 코딩


Out Stagram : 인스타그램 클론 프로젝트

오늘은 클론 프로젝트 주간에 정신이 없어서 작성하지 못했던 부분들을 다시 정리해보려고 한다.

클론 코딩 프로젝트 백엔드 Spring 4분과 프론트 React 2명, 총 6명이서 진행하였고 인스타그램 PC버을 클론 코딩하였다. 결과물은 다음과 같다.

- SA 보러 가기: https://www.notion.so/S-A-13db4f79c12e4f94a6eee28669fec243

- Github : https://github.com/17-outstagram/frontend

 

GitHub - 17-outstagram/frontend

Contribute to 17-outstagram/frontend development by creating an account on GitHub.

github.com

- Youtube 시연영상 : https://www.youtube.com/watch?v=MxVNrO2fpr4

 

 

프로젝트 기능

1. 회원가입 : 이미지 업로드, 이미지 미리보기, 이메일 인증, 유효성 검사(버튼 활성화)

2. 로그인 : Access-token과 Refresh-token을 사용한 로그인 인증, 인가 처리

3. 메인 페이지 : 인스타그램 피드 조회, 좋아요 기능

4. 사이드바 토글메뉴 : 포스팅(이미지 업로드, 미리보기)

5. 피드 상세 페이지 : 피드 수정 삭제, 댓글 조회 삭제

6. 기타 : 유저 페이지, 마이 페이지 게시물 조회, 유저 검색 기능, 팔로잉, 팔로우, 팔로잉한 유저의 게시글만 조회, 랜덤 유저의 게시물 조회, 좋아요 기능 등

 

 

시도한 점, 알게된 점

 

1. 로그인 페이지를 메인으로 사용 시 중첩라우팅 경로 설정 방법

로그인 페이지를 root경로로 사용하면서 중첩 라우팅으로 디자인 통일하기

문제) 기존 중첩라우팅 사용시 => /account/login으로 사용하기 때문에 로그인 페이지 경로를 /로 설정하지 못함

다음과 같이 해결 => path는 지정해 주지 않음

// Router.jsx
function Router() {
  return (
    <BrowserRouter>
      <Routes>
        <Route element={<AccountPage />}>
          <Route path="/" element={<LoginPage />}></Route>
          <Route path="/signup" element={<Signup />}></Route>
        </Route>
        <Route path="/main" element={<MainPage />}></Route>
        <Route path="/main/:id" element={<DetailPage />}></Route>
        <Route path="/my" element={<MyPage />}></Route>
        <Route path="/user" element={<UserPage />}></Route>
      </Routes>
    </BrowserRouter>
  );
}
//AccountPage.jsx

function AccountPage() {
  return (
    <div>
      Account <Outlet />
    </div>
  );
}

 

 

2. FormData는 콘솔에 찍히지 않는다.

FormData 안의 키와 값을 확인하기 위해서는 for문을 순회하여야 한다. 이부분을 몰라서 반나절 동안 데이터가 안들어가는 줄 알고 고생했다...ㅠㅠ

formData는 특수한 객체 형태이기 때문에 formData 안의 키와 값은 console에 찍히지 않는다는 것을 깨닫고, for문으로 formData 내부를 순회하여 키와 값이 있음을 확인하고 서버에 전송할 수 있었다.

 

3. FormData를 이용해 서버에 이미지 파일을 업로드 하는 방법

 

 

4. 이미지 파일 업로드 미리보기

 

5.Queries options

import { useQuery } from 'react-query'
 
function App() {
  const info = useQuery('todos', fetchTodoList, options)
}
  • options
    • enable : false로 설정하면 쿼리가 자동으로 호출되지 않는다. 즉 최초 선언시 호출을 막을 수 있다.
    • retry : 요청이 실패했을시 재요청을 실행한다. 기본값은 3이다.
    • refetchInterval : 일정한 간격으로 refetching이 가능하다.
    • refetchOnMount : mount되었을 때 refetch 여부를 결정한다. true라면 stale 상태일 때 refetch 한다. (booelan | "always")
    • staleTime : 데이터가 stale한 시점을 결정한다. 기본값은 0이다.
    • cacheTime : 캐싱된 데이터가 메모리에 남아있는 시간을 결정한다. 기본값은 5분(5 * 60 * 1000)이다.
    • 이 외에도 다양한 옵션들이 존재한다. 공식 문서를 확인해보자!

 

 

 

트러블 슈팅

 

1. 사용자 정보가 필요한 API요청에서 서버에 토큰을 전달할 때, headers 안에 set-cookie를 하여 전달하고자 하였는데 계속 access-token을 찾을 수 없다는 문제 발생. 

해결방법

 if (accessToken || refreshToken) {
    config.headers["accessToken"] = accessToken;
    config.headers["refreshToken"] = refreshToken;
    config.headers["userId"] = userId;
  }

프론트에서는 전달 받은 headers의 cookie의 정보를 읽고 저장할 수는 있지만 set-cookie를 할 수는 없다는 것을 알게 되었다. headers안에 access-token과 refresh-token 키로 값을 각각 전달하여 로그인 처리에 성공할 수 있었다.

 

2. intercepter response에서 액세스 토큰 만료 시 리프레쉬 토큰이 undefined가 되는 문제 발생

문제상황다음과 같이 코드에서 intercepter response를 받을 때 마다 토큰을 자동으로 저장하도록 하려고 했는데, 각각 토큰들을 서버에서 받지 못할 경우에는 undefined가 되어 저장되어 기존 토큰이 undefined되는 문제가 발생했다.

    const accessToken = response.data["accessToken"];
    const refreshToken = response.data["refreshToken"];
    const userId = response.data["userId"];
    if (accessToken || refreshToken) {
      sessionStorage.setItem("accessToken", accessToken);
      sessionStorage.setItem("refreshToken", refreshToken);
      sessionStorage.setItem("userId", userId);
    }
    return response;

해결방법

    const accessToken = response.data["accessToken"];
    const refreshToken = response.data["refreshToken"];
    const userId = response.data["userId"];

    if (accessToken) {
      sessionStorage.setItem("accessToken", accessToken);
    }
    if (refreshToken) {
      sessionStorage.setItem("refreshToken", refreshToken);
    }
    if (userId) {
      sessionStorage.setItem("userId", userId);
    }
    return response;

 

 

3. 검색 API에서 get 요청으로 body에 객체타입 데이터를 전송했는데, 서버에서는 계속 undefined로 뜨는 문제 발생

문제상황

get요청에서는 객체를 전달하지 못한다.

const searchUserAxios = async (value) => {
  try {
    const { data } = await instance.get("/api/search", { search: value });
    return data;
  } catch (error) {
    throw error;
  }
};

 

 

해결방법

쿼리문으로 변경해 데이터를 보내서 해결 하였다.

const searchUserAxios = async (value) => {
  try {
    const { data } = await instance.get(`/api/search/?search=${value}`);
    return data;
  } catch (error) {
    throw error;
  }
};

 

6. 매니저님께 질문한 부분들