20210815 리팩토링 Instagram 클론 프로젝트 by Redux-toolkit30 : 댓글 관련 컴포넌트 스타일링, 컴포넌트에 Comment Read, Create 연결 하기, Comment delete 구현하기

5 분 소요

리팩토링 Instagram 클론 프로젝트 by Redux-toolkit30



📄 프로젝트 설명


이 프로젝트는 기존에 React & firebase를 통해서 만든 인스타그램 클론 프로젝트 리팩토링 프로젝트 입니다. (해당 프로젝트는 프로젝트 카테고리에서 확인 가능합니다.)


상태 관리

해당 프로젝트에서는 redux-toolkit(Slice 모델)을 사용하여 상태관리를 구현하고 있습니다.


스타일

현재 SCSS를 채택하여 css 작업을 진행중에 있으며, 부분적으로 Material UI를 사용하고 있습니다. 대부분의 경우에는, Material UI와 React 호환성 문제로 대부분은 SCSS로 직접 구현하고 있습니다.




💻 화면 개요


체크는 현재 기능적으로 구현된 상황을 의미합니다.


  • 로딩 화면 또는 Component : 앱 실행 초기화 작업시 로딩 또는 다른 작업시 사용할 로딩 화면 및 Component
    • 스타일링 완료


  • 로그인 화면 : 기본 Email 로그인, Social 로그인, 로그인 에러
    • Email 로그인 : Email, Password input, 로그인 버튼
    • Social 로그인 : google로그인 버튼, github로그인 버튼
    • 로그인 에러 : Email로그인, google로그인, github 로그인 에러 발생시 사용자에게 출력


  • 회원가입 화면 : Email 로그인을 위한 계정을 만드는 화면, 회원가입 에러
    • Email 형식 가입 : Email, Password input, 회원가입 버튼
      • 가입시 사용자 Nickname 지정 input (추가 사항)


  • 피드 화면 : 사용 유저의 모든 게시글을 표시하는 화면
    • 게시글 박스 :
      • 타이틀 영역 : 최상단의 작성자 사진 + 이름, 게시글 수정 탭
        • 편집버튼 : 글 수정하기, 삭제하기 모달 -> 해당 버튼 누르면 삭제 또는 수정 페이지로 이동(아니면 모달이 수정하는 모달로 변경)
          • 삭제하기
          • 수정하기
      • 사진 영역 : 기존에는 1개만 가능했음 (욕심내면, 여러개 슬라이드 형식으로 가능하게 하고 싶음)
      • 내용 영역 : 게시글 내용


  • 글 작성 화면 : 글을 작성하는 화면
    • 이미지 리사이징


  • 현재 유저 프로필 화면 : 로그인한 현재 유저의 게시물과 대략적인 프로필를 표시하는 화면
    • 유저 프로필 수정하기 : 유저 프로필을 수정하는 화면 (userImage, userDisplayname, userIntro)
    • 작성 글 : 유저가 작성한 작성 글의 image 표 -> 클릭시 post detail
      • 작성 글 detail view : image 표에서 해당 이미지 클릭시 해당 글 detail view 화면
    • 로그아웃


  • 다른 유저 프로필 화면 : 다른 유저가 작성한 글의 유저 이름을 클릭하여 해당 유저의 프로필 화면 구현
    • 프로필 보기 : userImage, userDisplayname, userIntro
    • 작성 글 : 유저가 작성한 작성 글의 image 표 -> 클릭시 post detail
      • 작성 글 detail view : image 표에서 해당 이미지 클릭시 해당 글 detail view 화면


  • 네비게이션 바 : 앱로고 - 피드(Home)탭 - 글 작성탭 - 현재 유저 프로필(프로필 수정, 프로필 이동, 로그아웃) 탭
    • Navigation-profile 눌렀을 때 로그아웃, 프로필 수정, 프로필 이동 드롭 다운 필요


  • 무한 스크롤
    • 유저 스크롤 위치 기억 (뒤로가기가 아닌 페이지 변해도 기억 함)


  • 랜덤 유저 추천


  • 댓글 기능




📅 TIL (Today I Learned, 오늘 깨달은 것들)


2021.08.15 사항


1. 댓글 관련 컴포넌트 스타일링


PostControl 컴포넌트 스타일링

  • PostText와 PostImage 사이에 PostControl을 위치시킴
  • 좋아요의 하트 버튼, 댓글의 말풍선 버튼을 구성 함




댓글 페이지 스타일링


  • 댓글 페이지 스타일링
    • 댓글 페이지 배치 스타일링 : Navigation 아래 inner 안에 main, side가 양옆으로 나란히 있는 구성으로 배치함


  • CommentForm 컴포넌트 스타일링
    • fixed 형태가 아닌 flex를 걸어서, main 안에 CommentForm, comments_container가 나란히 존재하고 conmments_container 안에서 여러 comment가 overflow scroll 형태로 움직이게 함
    • submit 버튼 색
      • disabled 때는 회색
      • disabled가 제거된는 때 하늘색 (input 값이 있는 경우)
      • hover 시에는 파란색


  • Comment 스타일링
    • 각 Comment는 댓글 작성자 이미지, 작성자 이름, 댓글 내용이 들어가 있는 형태이다.
    • 작성자 이미지는 동그라미가 되게하고 작성자 이름은 a tag를 사용하여 굵게 처리함 (작성자 이름 클릭시 해당 작성자 profile로 이동할 수 있게)
    • 댓글을 span tag를 사용하고 mixins 로 지정한 기본적인 text 컬러로 지정




2. 컴포넌트에 Comment Read, Create 연결 하기

PostControlContainer

  • PostControlContainer에서 PostControl 컴포넌트로 goComments라는 함수를 생성하여 넘김
  • goComments 함수에서 getCommentsThunk는 postId를 인자로 받아 Read 요청하고, postId에 맞는 ‘/postId/comments’ path로 이동 시킴
  • goComments 함수를 말풍선 아이콘을 클릭시 실행
// ... 생략

const goComments = useCallback(async () => {
  await dispatch(getCommentsThunk(post.postId));
  history.push({ pathname: `/${post.postId}/comments`, state: { post } });
}, []);

// ...

CommentFormContainer

  • CommentFormContainer에서 CommentForm 컴포넌트로 onSubmit 함수 생성하여 넘기
  • onSubmit 함수에서 setCommentThunk는 postId와 comment를 인자로 받아 Create 요청
    • 그리고, input에 연결된 comment useState를 빈 문자열 ‘’ 상태로 초기화 함
// ... 생략

const onSubmit = useCallback(
  (event) => {
    event.preventDefault();
    dispatch(setCommentThunk({ postId, comment }));
    setComment("");
  },
  [dispatch, postId, comment]
);

// ...




3. Comment delete 구현하기


  • delete 구현시 고려할 점
    • Posts와 Comments를 따로 관리하기 때문에 Post, Comments가 상황에 일치 할 수 있도록 모두 신경 써야 함
    • 경우1) post가 글 작성자에 의해서 지워지는 경우, 모든 댓글도 같이 지워야 됨
    • 경우2) 댓글 작성자가 자신의 댓글만 지우는 경우
      • 이때, 만약 Post에도 2개의 comments view가 있는 경우 지우려는 댓글과 comments view에 있는 댓글과 일치하면, 반영해주어야 함


  • 현재는 간단하게 경우1 만 구현하여 해당 글의 댓글을 모두 지우는 요청으로 만들고, post delete 요청 함수안에 같이 요청하게 넣었다.
// 해당 글에 대한 댓글 모두 지우기 요청 함수
export const deleteCommentsThunk = createAsyncThunk(
  "redux-racstagram/comment/deleteCommentsThunk",
  async (postId, thunkAPI) => {
    try {
      const { docs } = await dbService
        .collection("comments")
        .where("postId", "==", postId)
        .get();
      const promises = docs.forEach((doc) => {
        dbService.collection("comments").doc(doc.id).delete();
      });
      await Promise.all(promises);
      return true;
    } catch ({ code, message }) {
      return thunkAPI.rejectWithValue({ code, message });
    }
  }
);
// 해당 글 지우기 요청 함수
export const deletePostThunk = createAsyncThunk(
  "redux-racstagram/post/deletePostThunk",
  async (post, thunkAPI) => {
    try {
      const {
        profile: { currentUser },
      } = await thunkAPI.getState();
      const { postId, postImageUrl, userId } = post;
      // 유저 방어 코드
      if (userId === currentUser.uid) {
        // 글 지우기 요청
        await dbService.collection("posts").doc(postId).delete();
        // 해당글의 모든 댓글 지우기 요청
        thunkAPI.dispatch(deleteCommentsThunk(postId));
        if (postImageUrl !== "") {
          await thunkAPI.dispatch(deleteImageUrlThunk(postImageUrl));
        }
      } else {
        throw new Error("Invalid user access!");
      }
      await thunkAPI.dispatch(resetImage());
      return true;
    } catch ({ code, message }) {
      return thunkAPI.rejectWithValue({ code, message });
    }
  }
);




다음에 필요한 사항

  • 댓글 좋아요 기능 -> 진행중
    • 기본적인 comments page, comment, commentForm 스타일링
    • comment read, create 요청 함수 컴포넌트에 연결 하기
    • post의 comments view 구현과 이에 맞게 comment create, read, delete 수정하기
    • comment update 구현하기


  • 자동 input 체크 (이름 중복 확인시)


  • 새 게시글 보기 버튼 또는 로고 클릭시 데이터 진입점 갱신 기능 구현하기


  • validation 구현 필요함
    • input 같은 경우, display none 적용시 browser에서 제공하는 validation 말풍선이 뜨지 않기 때문에 따로 구현 필요함
    • required를 사용하지 말고, submit 함수 단에서 input값이 들어 왔는지 체크하여 validation error 구현 필요
    • post 관련한 input의 check 대략적인 (PostUpdateContainer, postFormContainer)
    • auth 관련한 input의 check 대략적인 조건 구현
    • 각 input 별로 데이터 형태에 따른 구체적인 조건 설정이 필요함
      • 이메일, 패스워드, 유저 네임, 글 내용의 형식(조건, 제한) 지정 필요


  • 스켈레톤 UI 필요


  • propType으로 type 지정 또는 typeScript 도입


  • sementic tag 적절한 태그로 수정하기 (검토)


  • 효과적인 렌더링 제한을 위해서 container에 있는 함수들을 hook으로 만들어 구현하기


  • route ‘/profile’ pathName을 ‘/user/:userName’ pathName 사용하게 통합하여 pathname에 대한 조건을 줄여 보자


  • profileUpdateContainer과 postFormContainer 통합 시도


  • 글 작성 시간 (클라이언트 단에서 뿌리는 경우 로컬 시간 변경으로 조작 가능한지 테스트 필요함)




나중에 구현하고 싶은 기술


  • 댓글 기능
  • 좋아요 기능
  • 유저 이름 검색을 통한 프로필 보기 (이름 검색)
  • 게시글 장소 태그로 장소 지도 보기 (지도 API)

태그:

업데이트: