til

리액트 입문 5일 차 @Readme, return내 js, React아티클-hook

fpzmfks 2024. 8. 14. 21:27

오늘은 리액트 입문 메달리스트 개인과제 재제출 날이고, 동시에 리액트 챌린지반 수업일이다. 나는 전 날에 도전과제까지 다 마쳤기 때문에 개인과제 재제출을 할 것이 따로 보이지 않았는데, readme와 테이블 출력에 있어서 고칠 점이 있어서 반영하여 재제출을 했다. 

 

먼저 readme를 살펴보자면, 이전에는 정말 간결하게 글로 컴포넌트의 구조를 설명했지만 매니저님이 제시해주신 모범사례를 참고해서 트리 형태로 컴포넌트의 구조를 그려보았다. 또 주요 기능과 서브 기능을 나누어 제시하고 컴포넌트의 어느 위치에서 작동하는지 표시했다. 아래가 개선한 readme이다. 

 

App.jsx
├─Header.jsx
├─<form>
│ ├─MedalInput.jsx <-input 데이터 유효성 검사
│ ├─<button>추가 <-로컬 스토리지에 데이터 변경 반영
│ └─<button>업데이트 <-로컬 스토리지에 데이터 변경 반영
└─Table.jsx
│ ├─Th.jsx
│ └─List.jsx <-정렬
│ │ └─<button>삭제 <-로컬 스토리지에 데이터 변경 반영

주요 기능 -추가 -업데이트 -삭제

서브 기능 -정렬 -input 데이터 유효성 검사 -로컬 스토리지에 이전 데이터 저장

또 이렇게 다른 사람의 코드를 살펴보니 아주 쉽게 테이블 출력을 개선하는 방법이 보여서 내 코드에도 반영했다.

{list.length === 0 ? (
        <p>아직 데이터가 없습니다</p>
      ) : (<Table list={list} setList={setList} />)}

이러한 코드를 짜주면 데이터가 없을 때는 데이터가 없다는 html이 나타나고 데이터가 있으면 table이 출력되어서 무의미하게 테이블의 제목이 항시 노출되어 있는 것을 막을 수 있다.

 

여태껏 컴포넌트 return에서 js를 사용한 건 변수명이나 map을 입력하거나 if문을 사용했던 것 뿐이었는데, 이 코드를 보고 나니 html을 js로 조작할 수 있는 jsx의 장점이 크게 느껴졌다. 사실 데이터가 없을 때 테이블을 숨기는 기능을 생각해보기는 했는데, 이전에 하던대로 css로 display:none, flex하는 것밖에 생각이 안 나서 너무 번거로울 것 같아 그만두었다. 하지만 jsx에서는 html을 js로 쉽게 조작할 수 있으니 css 같은 다른 요소를 건드릴 필요 없이 이러한 코드로 동적 페이지를 만들 수 있는 것이다. 역시 같은 과제를 하는 다른 사람의 코드를 보니 배울 점이 많았다. 


이렇게 과제를 살펴보는 건 빨리 끝났고, 대부분의 시간은 react 챌린지 반 강의 튜터님이 제시해주신 react 아티클을 읽으며 시간을 보냈다. 일단 집중적으로 읽은 것은 'React는 Hooks를 배열로 관리하고 있다'라는 글이다. 

 

React란 내가 이번 캠프에서 직업 기술로 삼아 취업할 수 있을 정도로 잘 습득해야 하는 프론트엔드 개발 라이브러리이고, Hooks란 React에서 제공되는 기능이다. 정확히는 다르겠지만 arr.map과 비슷한 내장 함수 같은 것이라고 생각하고 있다. 

 

이러한 hook은 리액트를 이용하여 spa(single page application)를 만드는 데 중요한 역할을 하는데, 일단 내가 당장에 쓸 수 있는 유일한 hook인 useState로 예를 들어보고자 한다. 

 

useState는 이번에 React 입문 개인과제로 메달리스트 페이지를 작성할 때 사용한 hook이다. 구조분해할당으로 상태값상태값을 저장하는 함수를 빼내와서 변수로 저장하여서 사용할 수 있다. 

const [country, setCountry] = useState('')

 

그리고 뒤쪽 () 안에 초기값을 지정해서 사용할 수 있는데 아래와 같이 로컬스토리지에서 값을 가져오면 최초 렌더링 시에도 초기값을 상태값에 저장할 수 있다. 

const [list, setList] = useState(JSON.parse(localStorage.getItem('medal'))||[])

 

이후 이렇게 빼내온 [list, setList]를 사용해서 상태값을 변화시키고, 그때마다 해당 hook을 선언한 컴포넌트를 리렌더링 할 수 있다. 이렇게 컴포넌트를 리렌더링하면 동적페이지를 작성할 수 있다. 예를 들어 기본적인 CRUD, 즉 메달 추가, 메달 출력, 메달 업데이트, 메달 삭제와 같이 이번에 내가 구성한 페이지의 기능들이 이 함수를 사용한 리렌더링을 통해 이루어지는 것이다. 

 

그리고 위쪽 아티클에 의하면 이러한 hook은 배열로 관리되고 있다고 한다. 아티클의 작성자는 어째서 hook이 객체가 아닌 배열로 관리되고 있는지 의문으로 여겼다. 왜냐하면 객체로 데이터를 관리하면 key 값을 이용하여 데이터를 쉽게 다룰 수 있을 것 같지 않냐는 것이다. 기존에 배열로 관리되고 있는 hook은 호출 순서에 의존하고 있기 때문에 불편할 것 같다는 것이다. 하지만 작성자가 실험해본 바로, hook의 데이터를 객체처럼 다루면 작게는 key와 해당 객체를 다루기 위한 여러 변수와 함수의 이름을 짓는 것에서부터 다중상속문제, 조건부 선언에서 코드 파악이 힘듦, hook간에 데이터 전달 어려움 문제 등이 있었다. 

 

이름 짓기에 관한 문제는 말하면 입아프고, 다중상속문제는 일단 내가 이해하기로는 객체 특유의 문제이므로 편의성을 추구하다가 오히려 문제를 만들어버린 경우이다. 조건부에서 코드 파악이 힘든 문제는... 예시로 제시된 코드를 파악하지 못해서 잘 모르겠지만, 복잡한 코드 환경에서 배열보다 객체가 다루기 성가시다는 건 나 또한 잘 아는 바이다. 

 

가장 마지막 문제가 가장 치명적인 것 같은데 작성자가 말하기로는 hook을 객체로 관리하면 다음 hook에서 이전 hook의 값을 가져올 수 없다고 한다. 어림짐작하기로는 아주 불가능한 건 아닌 것 같은데, useSpring이라는 처음 보는 hook은 전달되는 값들이 객체의 형태로 복잡한 양상을 띠고 있어서 이를 더욱 복잡하게 객체로 관리되는 hook으로 사용하려면 아주 어려울 것 같기는 하다. 

 

이렇게 hook에 대해서 알아보았다. 잘 이해는 못했지만, 어쨌든 hook은 객체가 아니라 배열로 관리되고 있다는 것은 확실하게 이해했다. 그리고 이제 나에게 있어서 더 큰 시련은 앞으로 많이 사용하게 될 커스텀 훅을 만들어서 사용하는 것이다... 이제 이렇게 hook이 관리되고 있는 구조를 어렴풋이 이해했으니 커스텀 hook 또한 객체가 아닌 배열로 관리되도록 만들어야 한다는 것은 알았다. 다음 과제, 혹은 이미 완료한 과제를 리펙토링하면서 커스텀 hook에 대해서도 알아가야 할 것이다.