React - instagram 클론코딩 ver2

군밤먹으면서코딩·2021년 7월 1일
0

Projects

목록 보기
2/3
post-thumbnail

바닐라 js로 구현한 instagram 클론 프로젝트 => React로 바꿔보기!!

⚡️ 본격적으로 React를 사용해보면서 특히나 어려워했던 기능들/코드들을 기록해보려 한다. ( 다음엔 어려워하지말자!! )

주요 기능

  • MOCK 데이터를 활용해 component 재활용! (스토리,유저 추천,피드,댓글)

  • 로그인 기능 ( 이메일&&비밀번호 validation , 백엔드 팀원과 로그인 통신

  • 댓글 추가 / 좋아요 / 삭제 기능

etc - git을 통해 add,commit, push, pr생성 과정을 통해 git과 좀 더 친해진 것 같다 🤨

1. 컴포넌트의 분리(?)

  • 처음엔 컴포넌트들을 어떻게 나눠야 하나 고민이 많았다.
  • 이는 공식문서를 통해 이해할 수 있었는데, 요약하자면 다음과 같다.
    - 하나의 컴포넌트는 하나의 기능만 해야 한다!
    • 크게는 Nav,Story,Feed,Aside 네개로 나누고, 그 하위에 reply 컴포넌트를 추가하였다.
    • 반복되는 기능을 수행하는 것들은 컴포넌트로 쪼개주자!! ex) feed,reply, story
    • React 컴포넌트의 재사용성은 증말루 👍
  <>
        <Nav />
        <div className="main">
          <main id="main">
            <div className="mainContainer">
              <Story storysArray={storys} />
              {feeds.map((feed, index) => (
                <Feed
                  key={feed.id}
                  id={feed.id}
                  img={feed.imgs}
                  writer={feed.writer}
                  writerImg={feed.writerImg}
                  feedIdx={index}
                  introText={feed.introText}
                  feeds={feeds}
                  changeState={this.changeState}
                />
              ))}
            </div>
            <Aside recommands={recommands} />
          </main>
        </div>
      </>

2. State와 Props

확실히 이론을 볼때와 내 코드에 적용하는 것은 많은 차이가 있었다.
불필요한 부분을 제외하고 state가 변경된 부분만 제거하는 react는 나에게 있어서 너무 생소했다.

state만 신경써주면 된다!!! 내가 수정한 코드가 화면에 렌더링되지않는다?!
그럼 십중팔구 setState를 해주지 않았기 때문이다 ㅎㅎㅎ

⚡️ state를 결정하는 3가지 원칙!

  • 부모로 부터 props가 전달되는가? ❌
  • 프로젝트 내에서 변경되지 않는 값인가? ❌
  • 컴포넌트 내에서 다른 state나 props를 통해 가공할 수 있는가? ❌

위 3가지 모두 해당되지 않는다면 state로 지정하면 되겠다!!

예를 들어 내 소중한 feeds state의 경우가 이 3가지 원칙을 충족시키는 state라고 할 수 있다. 이후에 설명할 reply 추가/좋아요/삭제 기능 모두 이 feeds state를 통해 완성할 수 있었다!

3. 댓글 기능

⚡️ 댓글에 추가,삭제, 좋아요 기능을 넣는 부분이 가장 아리까리했다. 주요 코드들을 기록하면서 본격적인 프로젝트에 대비해 보자!

댓글 추가 기능

  • 우선 newFeed라는 변수를 만들어 부모 컴포넌트의 state인 feeds를 가져온다.

  • newFeed[this.props.feedIdx].replis 이 부분은 댓글 전체부분으로, 이 부분의 값들을 변경시켜줘야 하기 때문에 작성하였다.

  • ...전개연산자를 사용한 이유는 앞의 부분(댓글들) 부분을 유지하고 그 뒤에 댓글들을 추가하기 위함이다.

  • 이를 setState 해주는 함수를 부모 컴포넌트로 부터 받아오면 댓글 추가 함수를 완성할 수 있다!

  addReply = e => {
    const { content } = this.state;
    let newFeed = this.props.feeds;

    newFeed[this.props.feedIdx].replis = [
      ...newFeed[this.props.feedIdx].replis,
      {
        id: newFeed[this.props.feedIdx].replis.length + 1,
        userName: 'yongyong04',
        content: content,
        isLiked: false,
      },
    ];
    this.props.changeState(newFeed);
  };

댓글 좋아요 기능

이 부분을 처음에는 filter()를 활용해서 구현했다가, Feed+replys가 담긴 MOCK 데이터를 적용하였더니 좋아요 클릭 시 모든 데이터가 날아가버리는 현상이 발생해 수정하였다! 😭

  clickHeart = id => {
    let newFeed = this.props.feeds;
    newFeed[this.props.feedIdx].replis = newFeed[this.props.feedIdx].replis.map(
      reply => {
        if (reply.id === id) {
          reply.isLiked = !reply.isLiked;
        }
        return reply;
      }
    );

    this.props.changeState(newFeed);
  };
  • 좋아요 부분도 댓글 추가 부분과 흡사하다!

  • 해당 댓글의 isLiked만 ! 연산자를 통해 반대로 변경시켜주고, 전개 연산자를 필요로하지 않는다 정도!

  • 여기서 map()함수를 사용하는 이유는, 댓글 배열의 각 요소들을 돌면서 isLiked의 boolean 값을 확인하기 위함이다. ( 당연히 map인데 왜 filter를 썻을까..ㅎㅎ)

댓글 삭제 기능

 deleteReply = index => {
    let newFeed = this.props.feeds;

    newFeed[this.props.feedIdx].replis = newFeed[
      this.props.feedIdx
    ].replis.filter(element => {
      return element.id !== index;
    });
    this.props.changeState(newFeed);
  };
  • 댓글 삭제기능 또한 댓글배열이 존재하는 위치까지 접근하고,

  • 해당 index와 배열 요소의 인덱스가 일치하면 filtering 해주면 된다!

정리

바닐라 JS만 써보다 React를 써보니 컴포넌트의 재사용성이 정말 매력적인 라이브러리인것 같다! 이제 다음주면 백엔드와 협업 프로젝트를 진행하게 되는데, 잘 준비해서 더더욱 React에 익숙해지고 싶다!!!💪

2개의 댓글

comment-user-thumbnail
2021년 7월 1일

와 정말 열심히 하셨네요 !! ^^

1개의 답글