감을 잃지 않기 위한 2022 dev-matching 시험 후기

Kyung yup Lee·2022년 3월 13일
2

프론트엔드

목록 보기
20/20

dev-matching

데브매칭은 프로그래머스에서 주관하는, 이직이나 취업을 위한 프론트엔드 테스트이다.
바닐라 자바스크립트로 주어지는 요구사항을 구현해야 한다.

https://programmers.co.kr/competitions/2165

조건

기본적으로 vanilla js 만 사용해서 특정 웹페이지를 구현하거나, 특정 기능을 구현하는 과제이다.

  • 인터넷 검색 및 오픈북 참고 가능
  • 빈 종이와 볼펜 메모 사용 가능
  • 외부 IDE 사용 가능(메신저 프로그램, 계산기 등 외부 프로그램 절대 사용 금지)
  • 화장실 이용
  • 물, 음료, 간식, 껌 등 섭취

나는 특별히 오픈북을 할 수 있다는 부분에 집중했다.

이 얘기는 미리 코드를 만들어두고 적용 시킬 수 있다는 뜻이었고, 예전에 만들어 둔 바닐라 vDOM과 hooks 를 개선해서 적용해볼까 라는 생각을 했다.

https://velog.io/@lky9303/K%EC%82%AC-%EA%B3%BC%EC%A0%9C-%EC%A0%84%ED%98%95-%ED%9B%84%EA%B8%B0-%EB%B0%8F-%EC%A0%95%EB%A6%ACvirtual-DOM-hooks-%EB%B0%94%EB%8B%90%EB%9D%BC%EB%A1%9C-%EA%B5%AC%ED%98%84

추가 부분

event handler를 vDOM에서 처리

이전에 이벤트 핸들링하는 부분을 처리할 수 없어서 이벤트 위임을 통해 이벤트 처리를 했었는데, 이번 기회에 이벤트 처리를 하는 부분을 vDOM을 렌더링하는 과정에서 이벤트 바인딩을 하는 방법으로 변경했다.

	    const $el = document.createElement(node.type);
        node.props.forEach(item => {
          const propKey = Object.keys(item)[0]
          if(propKey.substr(0, 2) === 'on'){
            $el.addEventListener(propKey.substr(2), Object.values(item)[0])
          }
          else{
            $el.setAttribute(Object.keys(item)[0], Object.values(item)[0])
          }
        });

위 코드처럼 element를 만들 때, 프로퍼티 키의 앞에 on 이 있다면, 이벤트로 인식하고, on 뒤의 부분을 이벤트 형식으로 확인해 바인딩했다. 그 외의 경우에는 이벤트가 아닌 attribute로 인식해, setAttribute를 해준다.

이렇게 하면, 추가적인 이벤트 핸들링 함수를 만들 필요없이, 이벤트 콜백함수만 만들어서 이벤트 처리를 할 수 있다.

hooks 처리

상태값 예외처리

hooks 에서 버그가 많이 발생했었는데, 예전에는 이 hooks에 들어오는 상태값을 배열만을 전제하고 작성했기 때문이다.

hooks 내부에는 initialState와 이전 상태를 비교하는 부분이 있는데, 이 부분에서 || 를 사용한다.

하지만 이 상태값을 boolean 형식을 사용하거나, number형식을 사용할 경우, 내가 의도한 상태값이 들어가더라도, 이 상태값이 false나 0이라면, falsy한 값으로 인식해버려 버그가 발생했다.

_useStateStatus[currentHook] = _useStateStatus[currentHook] || initialState

이 부분을 문자열로 변경시켜서, 어떤 값이든 setState를 통해 값을 변화시켰다면, truthy 한 값으로 인식할 수 있도록 만들어주었다.

if(typeof initialState === 'boolean' || typeof initialState==='number') _useStateStatus[currentHook] = _useStateStatus[currentHook] || initialState + '';

if(typeof newState === 'boolean'|| typeof newState==='number') _useStateStatus[currentIdx] = newState + '';

위와 같이 변경하는 것을 통해 버그를 해결했다. 또한 이 상태값을 밖으로 내보낼 때는, 다시 boolean이나, number 형태로 변환해주어야 하기 때문에,

      (
        typeof _useStateStatus[currentIdx] === 'string' ?
        JSON.parse(_useStateStatus[currentIdx]) : 
        _useStateStatus[currentIdx]
      )

이렇게 다시 파싱해서 내보내주었다.

hooks 성능개선

같은 상태일 경우 return

상태값이 같을 때는, 렌더링을 다시 할 필요가 없다. 그래서 이전 상태값과, 새로운 상태값을 비교해서, 같은 경우에는 재렌더링을 막았다.

render 함수에 debounce 적용

현재 작성한 hooks는 너무 잦게 렌더함수를 호출한다. 하지만, 재렌더링은 모든 상태가 변경되고 마지막에 한번만 호출되면 되기 때문에, 디바운스를 사용해서, 마지막 한번만 렌더함수가 호출되도록, 200ms 로 디바운스를 적용했다.

hooks에 getState 함수 추가

변수로 상태값을 내보내도 상관이 없다고 생각했었는데, 이 부분에서 만들어지는 버그가 상당했다. 클로저로 인해서 발생하는 버그였는데, 각 컴포넌트가 모두 함수이기 때문에, 인수로 이 변수를 넘길 경우, 이 변수가 클로저가 될 여지가 있었다.

컴포넌트 내부에서 이벤트 콜백 함수를 작성하거나, 함수를 만들고, 이 상태 변수를 사용할 경우, 이 상태 변수가 클로저로 동작했다. 그래서 이 변수에 접근하면, 상태가 변경된 변수의 값을 가져오는 것이 아니라, 이전의 컴포넌트에 기록된 변수의 상태를 기억해, 그 값을 가져오게 되었다. 이렇게 되면, 갱신된 상태값을 불러올 수가 없게 된다.

그렇기 때문에 함수를 이용해서 hooks 내부의 상태값에 접근해야 한다.

데브매칭 후기

이번에는 어떤 특정 기능을 구현하는 것이었는데,

input이 있고, 그 인풋을 입력하는 순간, 해당 인풋으로 api 호출을 해 추천 검색어를 보여주고, 키보드를 통해 선택된 내용을 이동할 수 있도록 만들어준다. 그리고 엔터키를 눌러 검색을 할 경우, 위 쪽에 검색한 내역을 기록할 수 있도록 해주어야 했다.

5개 이상이 될 경우, queue처럼 가장 오래된 내용을 삭제하고, 중복된 내용이 있을 경우, 해당 내용을 삭제하고 신규 내용으로 push 하는 등의 추가적인 예외처리가 필요했다.

구현 내용 자체는 그렇게 어렵지 않았는데, 내가 만든 hooks에서 자잘자잘한 버그들이 있어, 그걸 해결하는데 시간을 꽤 소모했다. 그래서 추가 구현사항을 구현하지 못했는데, 조금 아쉬운 부분이 남았다.

다음에는 더 잘할 수 있을 것 같은 느낌.

응 광탈 ㅠ

profile
성장하는 개발자

2개의 댓글

comment-user-thumbnail
2022년 8월 24일

헉 유익하게 보다가 마지막에..
추가사항까지 구현해야 합격인가보네요..

1개의 답글