본문 바로가기
개발자 일기/일일회고 (TIL)

부트캠프 47, 48일차 (React Custom Component 과제)

by MS_developer 2022. 11. 1.

오늘의 생각

2일간 페어 과제를 진행했다.

 

우리에게 친숙한 UI 디자인 중 모달Modal, 토글Toggle 스위치, 탭Tab, 태그Tag, 자동완성Autocomplete, 클릭 편집(Click-To-Edit)을 구현했다.

 

꽤 기본적인 UI들을 막상 리액트를 통해 구현하려니 생각처럼 쉽지만은 않았다.

 

1. 모달 창

회심의 역작

 

모달 창은 이미 JS를 통해 만들어봤던 경험이 있었기 때문에 꽤 익숙한 존재였기 때문에 큰 위기는 없었다. 그래서 딴 짓을 많이 했다...

 

자동차가 굴러가기 위해 기름칠을 하는 느낌으로 가볍게 진행했고, Styled-Components와 리액트 전반의 기본적인 문법들을 잘 기억하고 있는지 점검할 수 있었다. 

 

배운 점
모달 창을 띄울 때는 position:fixed로 화면 고정 (position:absolute가 아님)
다른 컴포넌트와 겹쳐 보일 땐 z-index 조정
토글 형식의 boolean을 활용한 스테이트를 쓸 때는 NOT 연산자(!) 쓰기 (i.e. setState(!isState))

 

2. 토글Toggle 버튼

토글 스위치에서 가장 난해했던 부분은 Styled-component의 양식을 유지하면서 어떻게 해야 애니메이션적인 추가를 할 수 있는가에 대한 방법이었다.

 

이에 대한 정답은 의외로 간단했는데, 해당 HTML 요소에 사용하는 className에 삼항 연산자와 State를 적절히 활용해야 했다. 

 

/* 토글 형식의 애니메이션을 사용하기 위해
삼항연산자, 탬플릿 리터럴, 그리고 상태State를 적절히 활용한다
*/
const [isToggled, setisToggled] = useState(false);

const toggleHandler = () => {
    setisToggled(!isToggled);
  };

// ... 중략

<ToggleContainer onClick={toggleHandler}>

<div className={`container ${isToggled ? "toggle--checked" : ""}`} />
배운 점
토글 상태를 만들기 위한 State 생성 후, click 이벤트에 따라 상태가 바뀌게 설정하면 이에 따라 원하는 애니메이션을 가진 클래스명을 더하고 뺄 수 있다.

 

3. 탭Tab

 

탭의 경우 클릭에 따라 현재 선택 중인 탭을 강조할 수 있는 CSS 스타일링을 작성해야 했다. 현재 선택 중인 탭에 CSS를 추가하고 애니메이션을 적용시키는 방법은 기존의 토글과 크게 다르지 않았기 때문에 그대로 채용했다.  단, 이벤트 객체(event.target 등)를 사용하지 않고 현재 선택된 탭이 갱신되도록 함수를 작성해야하는 부분이 조금 헷갈렸다.

 

const sampleArr = [
    { index: 0, name: "Tab1", content: "Tab menu ONE" },
    { index: 1, name: "Tab2", content: "Tab menu TWO" },
    { index: 2, name: "Tab3", content: "Tab menu THREE" },
  ];


const selectMenuHandler = (index) => {
    setCurrentTab(index);
  };

// ... 중략

{sampleArr.map((el) => {
            const focusedTab =
              currentTab === el.index ? "submenu focused" : "submenu";
            return (
              <li
                className={focusedTab}
                key={el.index}
                onClick={() => {
                  selectMenuHandler(el.index);
                }}
              >
                {el.name}
              </li>
            );
          })}

 

이에 대한 해결책으로 State의 특성과 .map() 메서드를 통해 생성되는 컴포넌트에  맞는 이벤트리스너를 생성했다. 또한 각 요소에 index라는 속성에 고유한 수를 값으로 가지게 했다. 위 방법을 통해 기능을 적절히 구현하고 해당 탭이 집중(focused) 됐을 때 그에 걸맞는 CSS 스타일링을 추가했다.

 

 

4. 태그Tag

 

태그 UI의 경우 구현하는 기능이 다양했기 때문에 먼저 TODO 리스트를 작성했다.

 

/* TODO: 
 1. input 창에 텍스트 입력 후 Enter 키를 통해 태그가 추가 (addTags 메서드 실행)
 2. addTags 메서드 기능 구현
 2-1. 이미 입력되어 있는 태그라면 추가하지 않는 기능
 2-2. 아무것도 입력하지 않은 상태에서는 Enter 키를 눌러도 실행되지 않는 기능
 2-3. 태그가 추가되면 input 창을 초기화하는 기능
 3. 태그 이름 옆에 삭제 아이콘(x)이 표시 (클릭 시 removeTags 실행)
 3-1. X 아이콘 클릭 시 removeTags를 통해 태그가 삭제되도록 한다
 */

요구하는 기능은 다양했지만 TODO 리스트에서 정리된 순서대로 차근차근 진행해나가니 기능을 쉽게 구현할 수 있었다.

 

하지만 과제 제출을 위해 테스트를 확인해 본 결과, 한 가지 테스트 케이스를 계속해서 통과하지 못했다.

 

 

기존에 구현했던 기능의 경우 중복된 값을 입력했다면 input값을 빈 배열로 초기화 시켰다. 테스트 케이스를 면밀히 살펴본 결과, 같은 값을 입력하더라도 input 창에 값은 그대로 남아있길 원했던 것 같다. 이에 따라 같은 값을 입력하더라도 input값이 남아있게 조치했다.

 

 

배운 점
테스트 케이스가 요구하는 결과값이 무엇인지 정확히 몰랐기 때문에 해당 테스트 케이스 코드를 찾아보고 추적하는 부분이 어려웠다. 
기능적으로 잘 구현이 됨에도 테스트 케이스를 만족하기 위해 코드를 좀 더 조직이 원하는 방향대로 수정하는 부분도 쉽지 않았다. 하지만 만약 클라이언트가 요구하는 사항이 내가 구현한 기능과 조금이라도 다르다면, 클라이언트의 뜻에 맞춰 "완벽히" 요구한 기능을 수행해야 한다는 점도 다시 한 번 떠올릴 수 있는 좋은 계기였다.

 

5. 자동완성Autocomplete

 

자동완성의 경우 전체적으로 구현은 가능했으나 추가 도전과제에서 기능 구현과 테스트가 통과하는 가독성이 꽤 떨어지고, 코드의 과정이 복잡했다. (if문이 너무 많아서 읽기 힘들 때 느꼈다.)

 

오늘 진행한 세션에서는 모든 기능들을 구현하는 과정을 배웠는데, 이 과정에 특히 자동완성 UI의 경우 내 코드가 매우 비효율적이고 본래의 기능에 부합하지 못하다는 생각이 들었다.

 

레퍼런스 코드를 통해 구현된 UI

기본적인 접근에서부터 차이가 있었는데, 특히 키보드 움직임을 통해 특정 하이라이트가 구현되기 위한 코드를 미처 생각하지 못했었다.

 

배운 점
props 전달을 통해 useEffect 조건부 기능 실행 없이도 코드 구현이 가능하며, 해당 경우 의도치 않은 State 변경을 방지할 수 있다.
배웠던대로 Styled-Components에 props 전달을 통해 조건에 맞는 CSS를 구현할 수 있다.
기존 로직을 그대로 사용할 때 기존에 사용했던 이벤트리스너 메서드(i.e. handleDropDownClick)를 사용하면 코드를 효율적으로 재사용 할 수 있다. (즉, 이벤트리스너에 별도의 props 전달없이 기존에 선언되었던 이벤트리스너 메서드를 -당연하게도- 사용할 수 있다.)

 

6. 클릭 편집ClickToEdit

클릭 편집은 무리없이 모두 진행 가능했지만, CSS적으로 좀 더 성장할 수 있는 기회였다. 모든 기능이 구현 됐을 때, 클릭을 눌렀을 때 해당 input 요소가 조금 틀어지는 문제가 발생했다.

 

 

CSS 추적이 어려웠던 가장 큰 이유는 useRef를 통해 기능을 구현했고, 기존의 span 요소가 click 이벤트리스너를 호출될 시 기존 state (isEditMode)가 변경됨에 따라 input 요소로 변동되었기 때문에 직접적인 클릭이 되지 않았기 때문이다. 하지만 개발자 도구를 통해 기존 span 요소와 다르게 input 요소가 다른 스타일링이 적용된다는 것을 알게 됐고, 제공되었던 app.css 파일을 통해 다른 형식의 스타일이 적용됨을 알게 되었다.

 

제공된 template을 통해 진행함에 따라 발생했던 문제였는데, 의외로 곯머리를 앓았던 부분이었다.

 

이후 Styled-Component에 margin과 padding 속성에 값을 0으로 할당시켜 초기화를 시켰다.

 

 

이후 CSS 스타일링이 깔끔하게 적용이 되었다.

댓글