Instagram Clone Coding 2 : React & fetch Data

itssweetrain·2021년 4월 7일
1

project

목록 보기
2/8

프론트엔드와 백엔드의 첫 통신연결!

React의 적용과 Backend로부터 서버연결까지 완성한 인스타그램 클론코딩 미니 프로젝트 (´ ˘ `).。oO (♡)~

💡 주요 구현 사항

  • 자바스크립트로 구현했던 조건에 맞을 경우 로그인 버튼 활성화를 리액트로 변환
  • 댓글과 피드의 컴포넌트화
  • map() 함수와 mock data를 활용하여 컴포넌트의 재사용, 여러 개의 댓글과 피드 구현
  • fetch 함수를 통한 API의 호출

💡 중점적으로 생각한 것들

  • 배열 데이터 타입의 활용과 map() 함수의 사용
  • state와 props의 유동적인 사용
  • data 형식 받아오기 JASON VS JS
  • 비구조화 할당으로 Refactoring을 간결하게 해주기

💡 What I learned

리액트/Data 두 부분으로 나눠 작성하려고 한다.

  • 비구조화 할당
    익숙해지기만 하면 쉬운 비구조화 할당! ES6문법으로 리액트에서 반복적으로 써주는 값들을 간결하게 줄여줄 수 있다. 대표적으로 this.state, this.props 등이 있다.

    우리가 정의해준 함수 안에서 뿐만 아니라, render 함수 안에서도 state, props 객체에 비구조화 할당을 적용할 수 있다.

  • 라이프 사이클(componentDidMount)
    리액트의 Dom Tree가 작동하는 순간 동시에 호출 되고, 컴포넌트가 화면에 처음 표시된 후 한 번만 호출되므로 때문에 외부에서 데이터를 불러와야 할 경우, 네트워크 요청을 보내기 좋다. 이번 프로젝트에서도 서버의 data를 받아올 때 이용하여 렌더링과 동시에 호출되도록 설정하였다. 라이프 사이클은 이름처럼 일정 사이클이 있는데 Mount-Update-Delete 따로 블로그 정리를 해보려고 한다.

  • spread 연산자

const friends = ['Ryan', 'Appeach', 'Jordi'];
const addFriends = [...friends, 'Niniz'];
console.log(addFriends);
//['Ryan', 'Appeach', 'Jordi', 'Niniz']

기존의 배열의 값은 건드리지 않으면서 새로운 배열의 값을 추가적으로 넣는 연산자이다. spread 연산자는 컴마를 기준으로 앞 뒤로 위치를 변경해주면 순서대로 입력값이 들어간다.

첫 번째로 작성했던 식
concat을 이용하여 userCommentLists라는 배열에 입력하고 싶은 배열의 값을 합치려고 했다.

addText = () => {
  const { userComment, userCommentLists } = 
        this.state;
  
  this.setState({ 
   userCommentLists : userComment.concat([
    {
      id: userCommentLists.length + 1,
       userName: "itssweetrain",
       content: userComment,
    },
    ]),
  	userComment : '',
   });
};

두 번째로 concat 메소드 대신 spread 연산자를 이용하여 식을 더욱 간결하게 만들었다.

addText = () => {
   const { userComment, userCommentLists } = this.state;
   this.setState({
     userCommentLists : [
       ...userComment,
     {
     	id: userCommentLists.length + 1,
        userName: "itssweetrain",
        content: userComment,
     },
    ],
     userComment : '',
   });
};


//userComment.concat([{id~ 부분이 spread 연산자를 사용하면서 [...userComment, {로 바뀌었다!

마지막 Refactoring

addText = () => {
    const { userComment, userCommentLists } = this.state;
    const newCommentLists = [
      ...userCommentLists,
      {
        id: userCommentLists.length + 1,
        userName: "itssweetrain",
        content: userComment,
      },
    ];

    this.setState({
      userCommentLists: newCommentLists,
      userComment: "",
    });
  };

spread 연산자로 합쳐진 부분을 변수를 선언하여 묶어주고 setState에는 값만 넣어줄 수 있게 하였다. 이 부분에서는 멘토님의 리뷰를 받았는데, 여기서는 식이 길지 않으므로 두 번째로 수정한 것과 같이 setState안에 바로 업데이트 되는 값을 넣어주는 것이 더 바람직하지 않을까라는 의견을 들었다

  • mock data를 관리하는 두 가지 방법
    data.js는 고정 데이터를 분리시키고, data.json은 API에서 불러오는 동적 데이터이다.

    JS파일은 변수를 선언해줘야하고, 연결되는 파일에 import를 해줘야한다. 대신 JSON은 pubic 폴더에 위치하며 연결해줄 필요가 없다는 장점이 있다. 댓글에 넣어줄 데이터와 피드에 넣어줄 데이터를 각각의 방식으로 적용해보았다.

댓글 데이터를 담은 data.js 형식

const COMMENT = [
{
  id: 1,
  userName: "itsrealbean",
  content: "나도 같이 가자!",
  isLiked: true,
},
{
  id: 2,
  userName: "2w0",
  content: "봄바람 너무 좋지~",
  isLiked: false,
},
{
//생략
}
];

export default COMMENT;

피드 데이터를 담은 data.json 형식

[
    {
      "id": 1,
      "avatarImg" : "https://scontent-ssn1-1.cdninstagram.com/v/t51.2885-19/s150x150/164127914_286300409761070_3514065548199271682_n.jpg?tp=1&_nc_ht=scontent-ssn1-1.cdninstagram.com&_nc_ohc=hK9Z6hUsXFUAX8VrXlR&edm=AP_V10EAAAAA&ccb=7-4&oh=99e1f790312f7614bc04f2fe2629911e&oe=6093C4A4&_nc_sid=4f375e",
      "userName" : "chaeniblosson",
      "img" : "https://scontent-ssn1-1.cdninstagram.com/v/t51.2885-15/e35/s1080x1080/162530927_4235450509800844_8239822443609869086_n.jpg?tp=1&_nc_ht=scontent-ssn1-1.cdninstagram.com&_nc_cat=104&_nc_ohc=ur7wjCv78CYAX8LKPvi&edm=AP_V10EAAAAA&ccb=7-4&oh=d9a969351ee77ac35882276a3f567ebd&oe=60913EF0&_nc_sid=4f375e",
      "content" : "6개월만에 갔더니 신상 소금빵이 생겼다. 행복하다.",
      "hashtag" : "#베이커리봉교 #봉교 #상수맛집",
      "friendsName" : "eny_na",
      "friendsComment" : " 한입만🥖"
    
    },
    {
//생략}
  ]

JS의 객체로 이루어진 배열들을 저장한 변수명을 값으로 setState에 다시 업데이트 해주었고, 피드 데이터를 연결한 JSON파일을 받아온 data를 값을 넣어주면 된다.

componentDidMount() {
  fetch("http://localhost:3001/data/FeedData.json", {
    method: "GET",
  })
    .then((res) => res.json())
    .then((data) => {
      this.setState({
        feedLists: data,
      });
    });
  }  
    
componentDidMount() {
  this.setState({
    userCommentLists: COMMENT,
  });
}

Data 를 호출하는 법?

백앤드로부터 데이터를 받아오려면 api를 호출하고 데이터를 응답받아야한다. Web API는 클라이언트 측에서 사용할 수 있는 자바스크립트 내장함수로 fetch 함수를 사용했다. http 통신의 요청와 응답에 대한 이해가 있어야하며, 작성한 코드로 http를 간략하게 설명하자면

fetch를 선언하고 Data를 가져올 API주소를 입력한다음, method방식과 서버로 보내줄 입력값을 객체로 적어준다. 여기서는 로그인 시에 서버에 보낼 요청의 내용인 email과 password 값이다. 이 객체는 stringify되어 전달 받으며, 이 fetch 함수가 명령이 끝나고 난 후 (.then) 이에 대한 response를 다시 json 형식으로 바꿔주고 보내준다. 이 요청과 응답에 대한 이해를 잘 하고 있으면 식을 세우는데는 전혀 어려움이 없다!

POST와 GET의 차이?

Mock Data 과제를 할 때는, 단순히 직접 입력한 데이터 값을 받아와 화면에 나타내주기만 했기에 GET을 쓰면 되고 이 과제에서는 우리가 email과 password에 값을 입력해주어 다시 서버로 보내주어 유효성 검사를 해야하기 때문에 다시 보내줘야하는 값이 있을 땐 이와 같이 POST를 쓰면 된다.

로그인 & 회원가입 실습

checkValidation = () => {
    fetch("http://10.58.5.51:8000/user/signin", {
      method: "POST",
      body: JSON.stringify({
        email: "hykim10@nate.com",
        password: "rlagus0000",
        name: "joon",
      }),
    })
      .then((res) => res.json())
      .then((data) => {
        console.log(data);
        if (data["MESSAGE"] === "SUCCESS") {
          alert("Westagram 환영합니다");
          this.props.history.push("/MainP");
        }
        if (data["MESSAGE"] === "ALREADY_EXISTS_EMAIL") {
          alert("중복된 아이디와 비밀번호입니다.");
        }
      });
  };

console.log(data)를 확인해보니 서버에 저장된 id값과 password값이 같으면 MESSAGE로 SUCCESS가 나타나도록 객체로 값이 저장되어있었다. 이것을 클라이언트에게 보여지도록 if문과 alert 함수를 써서 환영메세지가 나오게 하고, 메인페이지로 넘어가도록 연결시켰다.

singup API로 변경 후, 같은 id값과 password값이 있다면 출력될 메세지값이 같은 방식으로 저장되어 있었고 다시 alert 창으로 클라이언트에게 중복됨을 알려주게 식을 작성하였다.

💡 What Should I Learn

  1. React 적인 사고

리액트의 목적을 생각하며 코드를 작성하는 연습!

리액트 컴포넌트를 쓰는 가장 큰 이유는 UI의 효율적인 재사용이다. 그렇기에 컴포넌트 구현시 단일 책임 원칙을 항상 염두해두어야 한다. 이는 하나의 컴포넌트는 한 가지의 일을 하도록 작성해야 된다는 것이다. 하나의 컴포넌트가 커지게 되면 보다 작은 하위 컴포넌트로 분리해야 하는 것이 이상적이다.

처음에 댓글창을 Main UI에서 따로 분리하고, 이 댓글창을 포함하는 Feed 또한 Main UI에서 분리했다. 댓글창의 상위 컴포넌트는 Feed지만 댓글창의 동적 구현을 하는 데이터들은 Main 파일에 작성한 것을 그대로 남겨두고 props로 받으려고 했다.

하지만 종속 부모 컴포넌트에 작성하는 것이 좋으므로 이 데이터들 또한 Feed 파일에 다시 옮겨주는 작업을 하였다. 보기에도 깔끔하고 동작 구현도 정상적으로 하는 것을 볼 수 있었다.

재사용하는 컴포넌트를 만들고 props를 이용해 데이터를 전달하는 큰 흐름을 이해하는 게 중요하다. props는 함수 매개변수처럼 부모로부터 분리된 컴포넌트에 전달되는 역할을 하고 state는 함수 내에서 선언된 변수처럼 컴포넌트 안에서 관리된다.

  1. Data 의 연결

직접 백엔드 서버를 받아와 실습해보니 요청과 응답에 대한 이해가 더욱 확실히 되었다. 백엔드의 서버에 나의 입력값이 잘 들어왔다는 200이 찍히는 순간을 본 기쁨은 자바스크립트 함수식 하나 실행되는 기쁨과는 세상다른 것이었다... 서버의 통신이 연결되고 원하는 데이터의 값이 출력되는 걸 직접 보니 나의 작업물이 점점 동적이고 생명이 부여된(!) 느낌이었다. 이렇게 프론트엔드와 백엔드의 첫 협업은 짜릿⭐️했고 앞으로 남은 프로젝트들이 더욱 기대된다! (⁎⁍̴̛ᴗ⁍̴̛⁎)

profile
motivation⚡️

0개의 댓글