밍부스31)트러블 슈팅 과 코드리뷰와 리팩토링을 겸한 혼종의 주저리

minji jeon·2022년 8월 11일
1

TIL_

목록 보기
47/61
post-thumbnail

1. 깃과 관련된 이슈

: 이번에 처음으로 a-z까지 깃으로 협업을 한거 같다. 전에는 올리는거 까지는 깃으로 하였지만 머지는 일명 손머지를 했었다. 이번에는 제대로 경험해보고자 . Organization 을 파고, 역할분담을 한뒤, 뼈대를 만들고,
각자 뼈대만든걸 합친뒤, 컴포넌트를 분리한 뒤 본격적인 작업으 시작하였다. 이 과정이 하루를 모두 쓸 만큼 고되고, 손이 많이 가는 작업이었지만 그뒤로 서로의 파일에 대한 충돌이 적어져 다음 작업들이 훨씬 수월해지고, 프로젝트 막바지가 갈수록 하길 잘했다는 생각이 들었다. 다만, 우리가 처음 겪는 문제들이 있었는데 pakage.json. yarn lock등에 서 발생하는 충돌은 막을 수가 없었다.심지어 저파일들은 한번 뒤틀리면 처음부터 세팅을 다시해주는 방법이 가장 수월할 정도로 골치아프다. 일단 나는 npm을 쓰고 팀원들은 yarn을 썻더니, 병합할때 그들의 깃에있던 yarn lock이 나한테도 깔리게 된다. 그리고 이 얀이 다른 사람 얀이랑 병합되면서 모두의 얀 패키지가 먹통이 되게되는 악순환이 반복되었다. yarnlock은 npm과 yarn과의 충돌을 막기위해 존재하기도 하여서 yarn과 npm을 섞어서 쓸때는 gitignore에 yarn을 넣으면 안된다. 그러니 패키지를 통일하자! 깃은 한번 추적을 시작하면 그 추척을 멈추지 않는다고 한다. 끈질긴놈같으니라고….그러니 시작할때부터 깃이그노어에 넣어놀것!!

이번주의 깨달음 —> 협업을 할때는 npm, yarn둘중에 하나로 통일하고, yarn lock은 git ignore에 넣어놓다.
Pakage.json, db.json도 모두 이그노어 넣어놓자.
git ignore의 필요성을 크게 느끼게 된 주였다. (이모든건 처음 시작할때 세팅할것)

2. 커스텀훅과 렌더링

onchange이벤트를 사용할 때 렌더링이 타이핑할때마다 돌아간다. 항상 이게 마음의 짐이었다. useref를 써야되나 했어야 했나 하는 생각을 했었다. 리팩토링겸 렌더링 테스트를 하면서 알게된 엄청난 사실은 input onchange이벤트를 useinput이라는 커스텀 훅으로 만들어서 사용하니 페이지에 돌지 않는다. hook은 컴포넌트로 종속되지 않으니 자식컴포넌트의 걱정도 할필요가 없을거 같다. 렌더링 문제가 잇을경우에도 사용을 고려해 봐야 겠다.
렌더링 검사시 부모컴포넌트는 정상적으로 렌더링되지만 자식컴포넌트가 두번 렌더링 된다. css작업을 하는 과정에서 레이아웃을 잡기 위해 싱글로그라는 컴포넌트안에 커멘트컴포넌트를 집어넣어놨더니 렌더링이 한번더 일어난 것이다. 리액트 프로젝트를 처음 만들때 레이아웃 컴포넌트 이딴거는 왜만드는 걸까 했는데 이런 이유에서 꼭 필요하다는 깨달음을 얻게 되었다. 레이아웃 컴포넌트를 만들고,코맨트와 싱글로그를 분리하여 다른 레이아웃에 두면 될거같다.

레이아웃컴포넌트를 적극활용하자. onchange이벤트를 자주사용한다면 커스텀훅도 고려해보자

3. 아토믹 디자인 ===생각보다 편리하다

프로젝트를 시작하기 전에 파일구조를 어떻게 할까 하다가, 아토믹 패턴이라는걸 알게되었고, 경험이 많지 않은 우리는 레퍼런스를 따라해보는것도 좋겠다 싶어서 아토믹패턴을 따라해보기로 하였다.
시작할때는 폴더가 많으니 헷갈리기만 하고, molecules에 뭟넣어야하는지, template에는 또 뭘 넣어야 하는지 영헷갈리기만 했는데 만들다 보니 이건 molecules면 되겠다, 이건 아톰이지 하고,슬슬 감이오기 시작했다. 이또한 기능별분리를 할수가 있어서 파일을 분리할때 명확하게 정해지니 편리했다.

4. 예외처리

예외처리의 중요성을 몰랐을 뿐더러 예외처리의 범위가 대체 어디까지인지도 감이오질 않았다. 예외처리를 고민할수록 꼭 고려해야 하는 요소라는 걸 알게되었다.

예외처리에는 문법적인 예외처리와 넓은 의미의 예외처리가 있다.
문법적인 예외처리라 하면 서버를 가져올때 try, catch와 같이 문법적으로 존재하는걸 의미하고, 넒은의미의 예외처리는 사용을 하면서 소비자의 예상치 못한 행동을 의미한다. '이름을 입력하시오' 라는 인풋이 있을때 해당유저는 이름이 없는 사람일 수도 있고, 이름이 문자가 아닐수도 있는것이다. 우리는 모른다 유저의 이름을....
문법적인 예외처리를 잘 하는 방법은 해당 함수의 독스를 꼼꼼히 읽어보는 것이다. 독스 읽어보면 '이런 상황에는 이렇게 하세요'라는 문구들이 있을것이다. 주의깊게 읽어보자..
그리고 타입스크립트가 각광받는것도 자바스크립트는 예외처리가 어렵기 때문이다..이또한 예외처리에 속함을 오늘알게되었다.
문법적 예외처리의 과정을 보자. 예외처리를 하지 않는 서버는 서버를 받아오는데 에러가 날 시, 사이트는 에러를 잡지못하고 사이트를 종료시켜버린다.
catch가 있다면 에러를 받고 그 에러가 자신의 범주에 있다면 약속한 답을 반환한다. 그래서 종료가 되지않는다. 만약 캐치를 못하면 원래대로 종료시켜 버린다.
다소 최근에 생긴 언어들은 예외처리가 필수 문법으로 들어가 있다고 한다. 그만큼 중요한 요소 임을 알아야한다.

5.프로젝트를 할때 고려해야 할 요소

: 프로젝트를 만들때 고려해야할요소는 코드 6, 그외 가 4라는걸 이번에 느끼게 되었다. .env라던가, 리덕스 데브툴베제라던가 가장 고생한 부분이 코드보다 이부분이었던거 같다. 내 나와바리가 아니니 아무리 구글링을 해도 무슨말인지 모르겟고, 의사가 환자의 어디가 아픈지 감조차 안오는 느낌이었다.
패키설정들에 관한것들도 좀 알아야할 필요가 있다는걸 느끼게된 한주였다.

6. 리액트렌더링

: 컴포넌트 내에서 엑시오스로 데이터를 불러올때 무한렌더링이 된다. 스테이트에 값이 들어오고 그게 리듀서로 들어가면 다시 액션에서 값을 불러고 다시 값이 스테이트로 들어가면서 무한렌더링이 일어나게 되는 것이다. 이를 위해서는 유즈이펙같은 훅 사용이 필수적이라고 생각되었는데, 이점에 대해 기술매니저님께 질문하니 훅과는 관련이 없으며, 렌더링에 대해 잘 고민해보고, 코드의 로직을 잘 생각해보라는 답변을 받게되었다. 답변이 조금 불만족스러웠지만 내가 렌더링에 대해 잘 모르고 있었구나라는 생각이들어서 다시 처음으로 돌아가 렌더링에 대해 고민해 보는시간을 가지려고 한다.
추후에 알게된 사실은 무한렌더링을 해결하기 위해 의도적으로 스테이트를 하나더 만들어 무한반복의 고리를 끊는 방법이 있다.
모든 코드가 그렇듯이 정답은 없으며 , 계속 나은방법을 고민하는것이 좋을거같다는 깨달음을 얻게되었다.
이번주발에 스테이트와 렌더링에 대한 공부를 다시 할것이다.

7. 리덕스 썽크

참고 : http://blog.hwahae.co.kr/all/tech/tech-tech/6946/
:이번에 처음 사용하게 되었는데 구현하기 급급하여 예시에 나온을 코드들을 막 갖다 썼다. 잘 돌아가긴 하지지만 좋은코드인가에 대한 의문이 들었다.
나는 builder라는 액션타입을 사용하였는데, 항해에서 추천한 방식은 map타입이었다. 이 두개의 차이점이 궁금하여 찾아보았다. 리덕스 아직 갈길이 멀구나...

RTK에서 case reducer(이하 케이스 리듀서)가 액션을 처리하는 두 가지 방법은 builder callback 표기법과 map object 표기법이 있습니다. 두 방법 모두 동일한 역할을 하지만 타입스크립트와의 호환성을 위해서는 builder callback 표기법이 더 선호됩니다.
Map Object 표기은 액션 타입 문자열을 ‘키’로 사용하는 객체를 받아서 케이스 리듀서에 맵핑합니다. 이는 builder callback 표기법보다 짧게 작성할 수 있다는 장점이 있기는 하지만 JavaScript를 사용하는 프로젝트에 유효한 방법입니다. TypeScript를 고려한다면 대부분의 경우 builder callback 표기법을 권장합니다.
createReducer의 콜백 함수 인자로 주어지는 builder 객체는 addCase, addMatcher, addDefaultCase라는 메서드를 제공합니다. 그리고 각 함수에서 액션을 리듀서에서 어떻게 처리할지를 정의할 수 있습니다

8. i번째 맵에서 i번째만 모달창만들기

{data.map((c, i) => {
       if (c.comment_id === param.id) {
         return (
           <div key={c.id}>
             <ListComment
               c={c}
               i={i}
               setModal={setModal}
               setSelectedIndex={setSelectedIndex}
             ></ListComment>

             {selectedIndex === i && modal && (
               //클릭이벤트 발생시 selectedindex스테이트에 
               //선택된 index값을 넣어준다. 해당인덱스 모달과 
               //스테이트 값이 일치할 시 모달을 열어준다.
               <EditComment
                 commentId={c.id}
                 setModal={setModal}
                 param={param.id}
                 editComment={c}
               />

9. 스타일드 컴포넌트 사용방법

스타일드 컴포넌트를 사용하면 마스터 버튼을 사용해야 했다.

import styled from "styled-components";

export const StBtn = styled.button`
  width: ${(props) => props.width || "5rem"};
  height: 2rem;

  cursor: pointer;

  border-radius: 20px;
  background-color: ${(props) => props.backgroundColor || "transparent"};
  color: ${(props) => props.color || "black"};
  border: ${(props) => props.border || "none"};

  &:hover {
    color: ${(props) => props.hoverColor};
    background-color: ${(props) => props.hoverBackgroundColor};
  }
`;

아래와 같이 버튼 컴포넌트를 만들어주면
태그안에 내가 원하는 내용을 넣을수도 있고, 프롭스를 주어 내가 원하는대로 설정도 가능하다.

<StBtn color="white" backgroundColor="#b8b8b8" width="6rem">

버튼은 위와 같이 사용 가능하다.

10. 아이디 이슈

json server를 이용하게 되면 알아서 아이디를 준다.
그래서 아이디는 not my business라고 생각했다......
하지만 이 아이가 수많은 버그들을 양성해 내고 말았다.......
나의 하루를 쏟아부은 버그.라고 쓰고, 바보멍청이 전민지라고 읽는다.
처음 발견 한 문제는 이랬다.
댓글을 수정하면 댓글이 수정은 되는데 화면에서 사라졌다.
아무래도 수정한 댓글을 리스트를 불러오는 코드가 못불러와서 그런는거 같은데 도대체 왜 그런 문제가 발생했는지 이해가 가질 않았다.
어제까지만 해도 잘 돌아간거 같은데… 배포도했고,,, 과제제출도 했는데 이런 문제가 발생한다고…?
지져스….
무엇이 도통 문제인지 감이안왔다. 어제랑 달라진게 없는데 왜그럴까!!
그래서 깃으로 시간여행을 해서 전날 밤 3커밋으로 전으로 되돌아갔다
거기서는 해당문제가 없었다. 그래서 이걸로 갈아끼워야지 했는데 그전에 3커밋동안 수정한내용을 보니깐 내가 id에 parseint를 넣어준 부분이 있어서 parseint만 넣어주고 이걸로 파일을 갈아끼워야지 했더니 버그가 튀어나왔다.

아하..이놈이 범인이었구나,,,,우선 모든 아이디를 전수조사해서 어디서 숫자고 어디서 문자인지 찾았지만, 컴포넌트가 유기적으로 이리저리 연결되어있다보니 찾기가 쉽지 않았다. 그래서 모든아이들을 문자 혹은 숫자로 통일하도록 함수를 넣어주었더니 해당문제는 해결이 되는데……… 다음 버그가 또 튀어나왔다. 내가 로직을 잘못짠건 알겠는데 어디가 문제인지 감이안와 콘솔을 일일이 찍어보며 고뇌에 빠졌다. 콘솔에 값을 찍어보니 undefined가 나온다. 근데또 기능은 잘돌아간다.어디서 잘못된 것일까…. 해당 버그와 함께 키를 주라는경고를 확인했다. 아니 나는 아이디로 이미 키값을 줬는데..? 이또한 수정했을때만 경고가 떴다.
그냥 제출할까 생각했던 순간 불현듯 아이디가 문제인가..?라는 생각이 들었다.
지금 생각해 보면 당연한 일이었다.
데이터값을 수정하는 로직이 아이디로 해당 값을 꺼내 값을 변경하고, 다시 집어넣어주는 로직인데 꺼낼때는 아이디가 있는데 값을 수정하고 넣는 과정에서 아이디를 안 넣어주니 당연이 에러가 날수밖에…. 근데 진짜 이런생각을 난 못했다…
모든건 알고리즘을 잘못짠 내탓이오..
가만보면 키를 아이디로 줬는데 자꾸 주라는 것도 이미 아이디에서 에러가 있다고 말해주는 것이었다. 알려주는데 왜 못알아먹니…?ㅋㅌㅌ

—>여기서 내가 기억할점 .

  1. 아이디를 잘주자 이아이는 중요한 아이다.
    아이디를 주는 방법에는 다양한 방법이 있는데 아이디를 주는 라이브러리를 사용하거나, date()함수를 예로 들 수 있다. 아이디 라이브러리는 겹치는 아이디를 주지않기 때문에 예외처리를 최소화 할 수 있을것이다.
  2. key를 아이디로 줬는데 자꾸 key를 안줬다고 경고를 한다..? 그럼 아이디가 문제인것이다.
  3. Useparam.id는 숫자를 스트링으로 반환한다

지금 이순간에도 새로운 버그를 찾았다. 글을 삭제하고 새로운 글을 만들었더니 과거의 댓글이 살아난다. 이건 다른사람들이 테스트를 하면서 알게되었다. —> 결론 테스트를 많이 해보자. 이또한 어떤 면에서는 예외처리에 속한다고 생각한다. 이 예외처리에 대해 많이 고민을 해야할거 같다. 이거또한 아이디주는것에서 발생한 문제이다.
그래서 음 그럼 같은 아이디를 가진 댓글을 삭제해 주면되겠구나 하고
그럼 버튼 클릭했을때 find함수로 같은 아이디 찾아서 댓글도 삭제해줘!라고 코드를 짰더니 , 댓글이 없을때는 찾은 아이디가 undefined로 나오기 때문에 거기서 또 에러가 나왔다. 예외를 생각하지 못한것이다. 그래서 결국 중첩이프문으로 코드를 짰다. 아직은 이코드가 작동하지만
이제는 계속 의심이 간다. 과연 버그가 없는 것일ㄲ ㅏ….

onClick={() => {
                     let found = data.find(
                       (element) =>
                         parseInt(element.comment_id) === parseInt(log.id)
                     );
                     if (window.confirm("정말로삭제하시겠습니까?")) {
                       if (found === undefined) {
                         dispatch(deletePost(log.id)).then(nav("/"));
                       } else {
                         found = found.id;
                         dispatch(deletePost(log.id));
                         dispatch(deleteComment(found)).then(nav("/"));
                       }
                     }
                   }}

11. 시간이 있다면 구현하고 싶은 기능들

  • 검색창을 만들고, 자동완성 기능
  • 페이지 네이션 기능
  • 로컬호스트에 아이디를 저장해주는 기능
  • 데이터 불러올 시 로딩중 기능
profile
은행을 뛰쳐나와 Deep Dive in javascript

0개의 댓글