React스럽게 코딩하기?

jh_leitmotif·2021년 12월 16일
0

Frontend 개인 공부

목록 보기
14/24
post-thumbnail

개요

올해 6월부터 11월까지 여러 쇼핑몰 사이트를 레퍼런스삼아 개인 연습용으로 작성하던 프로젝트가 있었습니다.

혼자 독학하다보니 이렇게 코딩하는 것이 맞나? 싶었는데

아니나 다를까, 이 코드를 처음 보신 멘토님의 말씀

이건 React 스럽지가 않은데요?

하시며 던져주신 키워드는 'Map' 함수였습니다.

약간 이런식으로 코딩한다고 보면 될 것 같아요
{
  renderArray.map((item)=>{
    <component props={item.id}/>
  }
}

이게... 무슨 소리지?

하며 당장은 어떤 의미인지 깨닫지 못했지만, 지금은 무엇인지 어렴풋이 알 것 같기도 합니다.


React의 철학

공식 홈페이지에서는 UI를 만들기 위한 JavaScript 라이브러리 라고 React를 소개합니다.

UI, 즉 사용자 인터페이스는 쉽게 생각하면 웹 페이지의 View입니다.

웹페이지나 모바일 환경 등등, UI는 어디에나 있고

글에는 '기승전결'이 있듯이, 인터페이스는 각각의 기능을 내포하는 조각으로 구성되어 있는 거구나! 라는 생각이 닿았습니다.

그러니까.. 웹 페이지에서는
사용자에게 항상 보여야하는 Navigation bar가 있고
핵심내용을 담는 Contents 영역이 있을 거고..
만약 광고를 넣고싶으면 사이드나 특정 영역에 Ad banner가 있겠지?
그리고 저작권이라던가...전화번호라던가... 그런 정보는 맨 아래에
있던 기억이 있구나!

제 문장으로 다시 정의해보면

거대한 틀 속에 각기 다른 기능을 가진 독립적인 개체들이
입맛에 맞게(?) 배치되어 있는 웹 서비스!

예전에 쓰던 코드 조각들

과연 어떤 코드였길래 React스럽지 않았을까?!

싶은 코드들을 자조적인 마음가짐으로 올려봅니다.

웅성웅성.. 이게 뭐야..?

그 때의 얕은 지식(?)을 되돌아봤을 때

예를 들어 DB에서 데이터를 가져오는 것에 성공했다면

axios.get('/api/getData')
.then(res=>{
  if (res.data.status){
    setClothesMap(true)
  }
 )

의류 Map의 state를 업데이트하고,

table 형태로 되어있는 영역에 하나하나 element를 받아온 정보를 담아

생성하여 붙여주면 되겠다! 라는 생각이었습니다.

하지만 이것은 DOM을 직접 건드리는 것이기 때문에 React에 반하고

React 공식 홈페이지에 작성되어있듯

간단한 뷰가 전혀 아니었던 것입니다.

아하... 내가 '절차형 프로그래밍'에 매몰되어 있었구나

라는 생각으로 자기 반성을 했던 순간이었습니다.


선언형(declarative) vs 명령형(imperative)

대학교 1학년 때 가장 처음 접했던 언어는 C 였습니다.

그래서 누구나 알다시피, Hello, world! 부터 시작해 징글징글하게 사용하고 있는 for 문에 익숙해있었죠.

#include <stdio.h>
int main(){
 int testArr = [0,1,2,3,4]
 int maxNumber = 0;
 for (i=0; i<testArr.length; i++){
   if (maxNumber<testArr[i]){
     maxNumber = i;
  }
 }
}

간단한 예제 코드를 작성했습니다.

한글로 순서를 정의해보면 다음과 같겠죠?

1. 전달받은 testArr 배열이 있고, 여기서 가장 큰 값을 구할거다!
2. 그러면 배열을 모두 순회하면서..
3. 현재 가지고 있는 최대값보다 순회 중인 값이 더 크다면!
4. 최대값을 다시 업데이트해주자!

이것은 컴퓨터에게 이 순서대로 이러이러한 작업을 해라! 라고 알려주는 것으로 '절차형', '명령형' 구조를 가지고 있습니다.

이와 반대로, 선언형어떤 작업을 하라고 이야기할 뿐이지, 그 작업을 '어떻게' 하는지에 대해선 알려주지 않습니다.

일상 생활 속에서 예시를 찾아본다면..

# 명령형의 경우....
 *** 라면 끓이기 ***
1. 봉지를 뜯는다
2. 물을 올린다.
3. 물이 끓으면 스프를 넣고, 건더기 스프를 넣고 면을 넣는다.
4. 4분 후에 맛있게 먹는다!
5. 김치를 꺼낸다.
6. 김치를 그릇에 담아 라면과 같이 먹자.
# 선언형의 경우...
1. 라면을 끓인다.
2. 김치를 반찬으로 먹는다.

즉, 명령형은 어떠한 동작에 대한 세부적인 명세에 집중하는 것이고

선언형은 무슨 동작을 하는지에만 관심을 두면 되는 것입니다.

그럼 앞의 코드로 돌아가서 생각해봤을 때...

아하..! 난 전혀 React 스럽게 코딩하고 있지 않는 거구나...

라는 도출이 가볍게 떠올라버리고 만 것이었습니다.


Do it like React! is it correct?

위의 결론까지 나온 뒤, 저는 생각을 바꾸기로 했습니다.

그럼 최상위에 있는 페이지에서
기능에 대해 명세하는 것이 아니라, 각 기능을 독립적인 컴포넌트로 만들어서
배치시키기만 하는 용도로만 사용해보자.

예를 든다면, 다음과 같은 생각입니다.

export default Main(props){
 return(
  <>
   <navBar/>
   <contentsArea/>
   <adBanner/>
   <footer/>
  </>
)}

그리고 작업에 대한 명세는 각 컴포넌트가 알아서 하도록 내버려 두는거죠.

그렇다면 map 함수가 왜 키워드가 된거지?

이 부분은 '댓글 달기' 기능을 구현해볼 때 이해가 바로 됐습니다.

우선은 최상위 컴포넌트만 명령형일 필요는 없다라는 생각이 있었습니다.

예를 들어 인스타그램 피드는
1. 프로필 헤더 영역
2. 피드 이미지 영역
3. 댓글 렌더링 영역
4. 댓글 작성 영역
네 개의 각각의 컴포넌트로 구성될 수 있는 거니까..
<Main> 밑에 <Feed>가 있고
<Feed> 밑에 <Header>, <FeedImg>, <CommentBox>, <InputComment>
이렇게도 구성되면 되는거지~

그렇다면, 댓글은 실시간으로 달릴텐데... 이걸 어떻게 렌더링을 해야하지? 라는 생각이 들었고,

여기서 실시간으로 받아오는 데이터를 state에 넣고
map 함수를 돌려가면서 컴포넌트를 렌더링해주면 되는거 아냐?

이런 발상에 만든 코드는..!

예전에 썼던 코드대로라면

const divTag = document.createElement('div')
divTag.id = 'feedCommentsBox'
.........주저리주저리

이렇게 써서 한없이 길어졌을 부분이 이렇게 깔끔하게 정리됐습니다.

이런 생각으로 조각들을 모으며 만든 최상위의 메인 코드는 아래와 같습니다.

위의 댓글을 다는 기능은 FeedComponent 내부에

명령형으로 FeedCommentComponent로 살아 숨쉬고 있습니다.

(뭔가 해냈다는 기분이 들어버린...)

메인페이지에는 Navbar가 최상단에 있고
실시간으로 받아오는 feed 데이터가 map함수를 통해 계속 그려질 것이고
Sidebar가 오른쪽에 있다.
그 각각의 작업은 Main이 알바가 아니고, 그건 컴포넌트 내에서
알아서 명세하든가 말든가 해라!

마무리

정답은 여러가지가 있겠지만

바로 위의 메인 코드를 멘토님께 보여드리니

내가 그 때 그 코드 봤을 때 뭔 생각했을지 이제 알겠죠 ㅋㅋㅋ

이미 볼륨이 커질대로 커져버린 잘못된 Repo지만

아... 내가 이렇게 이상하게 짜던 적이 있었지 ㅠㅠ

하며 마음을 다잡는 깡통으로 남겨둘 생각입니다.

언젠가 면접이 됐든, 어떤 상황이건 누군가가

'왜 리액트를 사용하시는 건가요?' 라고 물어봤을 때

어떻게 답변해야할지 가닥이 잡힌 것 같은 저번 주 였습니다

다음 정리할 포스트는 아직은 모르겠지만

'React props drilling' 에 대해 생각해볼 예정입니다.

profile
Define the undefined.

0개의 댓글