logosvg한 입 크기로 잘라먹는 리액트
Search

1. 컴포넌트

개발자들은 리액트를 컴포넌트 기반의 UI 라이브러리(Component-Based UI Library) 라고 소개합니다. 페이지의 모든 요소를 컴포넌트 단위로 쪼개어 개발하고, 완성된 컴포넌트를 마치 레고 조립하듯이 하나로 합쳐 페이지를 구성하기 때문입니다. 리액트로 웹 서비스를 개발할 때는 컴포넌트를 여러 개 만들어 이를 적절히 조합해서 만들곤 합니다. 이번 절에서는 리액트의 핵심 개념 중 하나인 컴포넌트를 자세히 살펴보겠습니다.
 

실습 환경 설정하기

본격적인 실습에 앞서 5장에서 사용할 새 리액트 앱을 만들겠습니다. 실습 환경 구축은 4장에서 Create React App으로 chapter4 리액트 앱을 생성했던 방법과 동일합니다.

리액트 앱 만들기

문서(Documents) 폴더 아래에 chapter5 폴더를 만든 다음 비주얼 스튜디오 코드에서 생성한 폴더를 엽니다. 단축키 <Ctrl>+<J>를 눌러 터미널을 열고, 다음 명령어로 새로운 리액트 앱을 만듭니다.
코드를 불러오는 중 입니다 ...

사용하지 않는 파일 삭제하기

혼동을 피하고자 src 폴더에서 실습에 사용하지 않을 파일 일부를 제거합니다.
다음 파일을 제거합니다.
  • src/App.test.js
  • src/logo.svg
  • src/reportWebVitals.js 
  • src/setupTest.js
이 파일들은 Create React App이 자동으로 생성한 파일들로 테스트 코드를 작성하거나 리액트 앱의 성능을 살필 때 사용합니다. 진행할 실습에서는 사용하지 않으므로 삭제합니다.
✋🏼
테스트 코드는 코드가 정상적으로 실행되는지 실제 프로그램 작동 전에 테스트를 목적으로 작성하는 코드입니다.
파일을 모두 삭제하면 src 폴더는 다음 그림과 같은 상태가 됩니다.
4개의 파일을 삭제하고 난 후의 src 폴더
4개의 파일을 삭제하고 난 후의 src 폴더

사용하지 않을 코드 삭제하기

이번에는 Create React App이 자동으로 생성하지만, 실습에서 사용하지 않을 코드를 모두 삭제합니다.
다음과 같이 src 폴더의 index.js에서 주석//으로 표시한 코드는 모두 삭제합니다.
코드를 불러오는 중 입니다 ...
reportWebVitals.js는 앞서 삭제한 파일 가운데 하나입니다. 이 파일을 불러오는 import 문을 삭제합니다. reportWebVitals는 리액트 앱의 성능 측정 용도로 사용하는 파일입니다. React.StrictMode는 리액트 앱 내부의 잠재적인 문제를 검사하는 도구입니다. 프로그래머가 예상하지 못한 코드상의 부작용을 탐지하거나 구 버전 리액트 기능을 사용하는지 등을 살핍니다. 이 설정이 있으면 리액트 입문자에게 혼란을 줄 수 있어 제거합니다. ③ ②와 동일한 이유로 삭제합니다.  ④ ①과 동일한 이유로 삭제합니다.
추가로 사이에 있는 주석도 모두 제거합니다. 불필요한 코드를 제거하면 index.js의 코드는 다음과 같습니다.
코드를 불러오는 중 입니다 ...
다음으로 src 폴더의 App.js에서 사용하지 않을 코드를 삭제합니다.
코드를 불러오는 중 입니다 ...
src 폴더의 logo.svg는 앞서 삭제한 파일이므로 해당 파일을 불러오는 import 문을 삭제합니다.  사용하지 않을 <header> 태그 전체를 삭제합니다.
불필요한 코드를 모두 삭제하면 App.js는 다음과 같이 단순해집니다.
코드를 불러오는 중 입니다 ...
<div className='App'>를 삭제하면 오류가 발생합니다. JSX 문법을 위반하기 때문입니다. JSX 문법에 대해서는 다음 절에서 자세히 다루겠습니다.
불필요한 파일과 코드를 모두 제거했다면, 터미널에서 npm run start 명령으로 리액트 앱을 시작합니다. App.js의 내용을 대부분 삭제했으므로 빈 페이지가 나옵니다. 오류가 아니므로 걱정하지 않아도 됩니다.

첫 컴포넌트 만들기

리액트 컴포넌트는 주로 자바스크립트의 클래스나 함수를 이용해 만듭니다. 클래스로 컴포넌트를 만드는 방식은 기본 설정 코드를 작성하는 등 함수로 만드는 컴포넌트에 비해 단점이 많아 지금은 선호하지 않습니다. 리액트 공식 문서에서도 클래스보다는 함수로 컴포넌트를 만들 것을 권장하고 있습니다. 이 책에서도 다루지 않습니다.

함수 컴포넌트 만들기

함수를 이용해 App.js에서 첫 번째 리액트 컴포넌트를 만들겠습니다. App.js를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...
함수를 이용해 Header라는 이름의 컴포넌트를 App 컴포넌트 밖에서 만듭니다.  Header 컴포넌트는 HTML을 반환합니다. 여러 줄로 이루어진 HTML을 반환할 때는 return 문에서 반환할 HTML을 소괄호로 감싼 다음 세미콜론(;)을 꼭 붙여 주어야 합니다.
페이지에서 헤더 역할을 담당할 Header 컴포넌트를 만들었습니다. 이렇듯 함수를 이용하면 매우 간단하게 리액트 컴포넌트를 만들 수 있습니다. 즉, 함수를 선언하고 해당 함수가 HTML 요소를 반환하도록 만들면 됩니다. 함수를 사용해 만든 컴포넌트를 특별히 함수 컴포넌트라고 합니다.
현재 Header 컴포넌트는 페이지에 렌더링하는 아무런 설정도 하지 않았기 때문에 저장(<CTRL>+<S>)해도 빈 페이지만 표시할 뿐입니다. 참고로 함수 선언식이 아니라 화살표 함수로도 컴포넌트를 만들 수 있습니다.
코드를 불러오는 중 입니다 ...
화살표 함수를 이용해 Header 컴포넌트를 만듭니다.
화살표 함수를 이용하면 컴포넌트 코드를 훨씬 간결하게 만들 수 있습니다.
✋🏼
컴포넌트의 이름은 항상 대문자로 시작하기
함수 컴포넌트를 만들 때 한 가지 주의할 점이 있습니다. 컴포넌트 함수 이름의 첫 글자는 항상 영어 대문자여야 합니다. 그 이유는 리액트 컴포넌트를 HTML 태그와 구분하기 위해서입니다. 
코드를 불러오는 중 입니다 ...
컴포넌트 이름의 첫 글자를 대문자로 작성하지 않아도 에러가 발생하지는 않습니다. 그러나 정상적인 리액트 컴포넌트로 인식하지 않기 때문에 의도치 않은 결과가 나타날 수 있으며, 리액트가 제공하는 여러 유용한 기능도 사용할 수 없습니다.

컴포넌트를 페이지에 렌더링하기

Header 컴포넌트를 페이지에 렌더링하려면 App에서 이 컴포넌트를 자식 요소로 배치해야 합니다. App 컴포넌트를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...
App의 return 문에서 Header 컴포넌트를 마치 HTML처럼 태그로 감싸 작성합니다.
✋🏼
리액트 컴포넌트를 반환하는 HTML 태그는 닫는 태그를 반드시 표기해야 합니다. 이를 JSX의 닫힘 규칙이라고 합니다.
리액트는 다른 컴포넌트를 태그로 감싸 사용합니다. 이때 App처럼 다른 컴포넌트를 return 문 내부에 포함하는 컴포넌트를 ‘부모 컴포넌트’라고 합니다. 반대로 Header 처럼 App의 return 문에 포함된 컴포넌트를 ‘자식 컴포넌트’라고 합니다. 이렇게 부모의 return 문에 자식을 포함하는 행위를 “자식 컴포넌트를 배치한다”라고 표현합니다.
Header를 App의 자식 컴포넌트로 배치했다면, 저장하고 페이지에서 어떤 변화가 있는지 확인합니다.
자식인 Header 컴포넌트를 페이지에 표시
자식인 Header 컴포넌트를 페이지에 표시
Header 컴포넌트를 페이지에 렌더링했습니다.

컴포넌트의 계층 구조

앞서 App에서 Header 컴포넌트를 자식으로 배치했더니 페이지에서 Header를 렌더링했습니다. 왜 그런 걸까요?
그 이유는 리액트가 컴포넌트를 페이지에 렌더링하는 과정을 되짚어 보면 쉽게 이해할 수 있습니다. 4장에서 Create React App으로 생성한 리액트 앱의 구성을 배우면서 index.js를 잠시 살펴본 적이 있습니다. index.js에서는 App 컴포넌트를 리액트의 루트 요소 아래에 배치해 렌더링한다고 하였습니다.
기억을 되살리는 의미에서 index.js 파일을 다시 클릭합니다.
코드를 불러오는 중 입니다 ...
리액트의 루트 요소 아래에 App 컴포넌트를 배치해 렌더링합니다.
index.js를 보면 페이지에 렌더링하는 컴포넌트는 App 하나뿐입니다. 따라서 새로운 컴포넌트를 페이지에 렌더링하려면 이 컴포넌트를 App의 자식으로 배치해야 합니다. 단지 컴포넌트를 생성한다고 해서 바로 페이지에 렌더링하지는 않습니다.
리액트에서 부모는 자식 컴포넌트의 모든 HTML을 함께 반환합니다. 예컨대 chapter5 앱이라면 App는 Header 컴포넌트의 HTML도 함께 반환합니다. 따라서 Header를 자식으로 배치한 App 컴포넌트의 예는 HTML로 작성한 다음 코드와 의미상으로 동일합니다.
코드를 불러오는 중 입니다 ...
자식 컴포넌트 Header의 반환값과 동일한 HTML 코드입니다.
리액트는 자식으로 배치한 컴포넌트를 부모와 함께 렌더링합니다. 만약 페이지에 렌더링할 컴포넌트가 다음 그림 처럼 3개가 필요하다면, 각각을 컴포넌트로 만든 다음 App의 자식으로 배치해야 합니다.
부모 App에 3개의 자식 컴포넌트 Header, Body, Footer 배
치하기
부모 App에 3개의 자식 컴포넌트 Header, Body, Footer 배 치하기
리액트에서 컴포넌트를 페이지에 렌더링하려면, App의 자식으로 배치하거나 Header처럼 자식으로 이미 배치된 컴포넌트의 또 다른 자식으로 배치해야 합니다.
리액트 컴포넌트는 위 그림 처럼 부모-자식관계라는 계층 구조를 형성합니다. 컴포넌트의 계층 구조를 다른 말로 ‘컴포넌트 트리’라고 합니다. 그리고 컴포넌트 트리에서 App는 항상 최상위에 존재하므로 이를 루트 컴포넌트라고 부릅니다.

컴포넌트별로 파일 분리하기

리액트에서는 보통 하나의 파일에 하나의 컴포넌트를 만듭니다. 이유는 하나의 파일에 여러 컴포넌트를 만들면 코드의 가독성이 떨어지기 때문입니다.
이번에는 컴포넌트를 여러 파일로 나누고, App.js에서 불러와 App 컴포넌트의 자식으로 배치하겠습니다. 그 전에 컴포넌트 파일만을 따로 모아 보관할 폴더를 하나 만들겠습니다.
리액트 앱 chapter5의 src에 component라는 이름으로 폴더를 만듭니다. 계속해서 이 폴더에 Header 컴포넌트를 담당할 Header.js를 생성합니다.
component 폴더에 Header.js 생성
component 폴더에 Header.js 생성
✋🏼
비주얼 스튜디오 코드의 폴더 생성은 새파일 아이콘 옆에 있는 새 폴더 아이콘을 클릭하면 됩니다.
Header.js에서 다음과 같이 컴포넌트를 작성하고 내보냅니다.
코드를 불러오는 중 입니다 ...
Header 컴포넌트를 다른 파일에서 사용할 수 있도록 내보냅니다. 이때 원하는 이름으로 불러올 수 있도록 모듈의 기본값으로 내보냅니다.
App.js에서 App 컴포넌트 바깥에 만들었던 Header 코드는 모두 삭제합니다.
코드를 불러오는 중 입니다 ...
Header 컴포넌트를 삭제하고 저장하면 페이지에서 오류가 발생합니다. 이 는 App 컴포넌트의 자식으로 배치한 Header를 찾을 수 없기 때문입니다.
Header 컴포넌트를 정의하지 않았다는 오류 메시지
Header 컴포넌트를 정의하지 않았다는 오류 메시지
오류가 발생한 이유는 Header 컴포넌트가 App.js에 선언되어 있지 않고, 다 른 파일에서 불러오지도 않기 때문입니다. 리액트에서 선언되지 않은 컴포넌트를 사용할 때, “(컴포넌트 이름) is notdefined”와 같은 오류가 발생합니다.
✋🏼
오류 메시지에 당황할 필요 없습니다.
위 그림의 오류 메시지를 보면 오류가 발생한 파일 src/App.js에서 Header가 정의되지 않았다고 알려줍니다. 따라서 Header 컴포넌트를 선언했는지 또는 다른 파일에서 불러왔는지 확인하면 금세 오류의 원인이 무엇인지 찾을 수 있습니다.
대다수 프로그래밍 언어나 도구들은 친절한 오류 메시지를 제공합니다. 따라서 오류가 발생하면 당황하지 말고 메시지를 천천히 읽으며 그 원인을 생각해 보세요. 해결의 실마리를 쉽게 찾을 수 있습니다.
오류를 해결하려면 App.js에서 Header 컴포넌트를 불러와야 합니다.
코드를 불러오는 중 입니다 ...
Header.js에서 기본값으로 내보낸 Header 컴포넌트를 App.js로 불러옵니다. 이때 경로 ‘./component/Header’의 ‘.’은 지금 작성하고 있는 파일(App.js)이 있는 위치를 나타낼 때 사용하는 표현입니다. Header.js는 component 폴더에 있으므로 현재 위치를 기준으로 경로를 표시해 불러 와야 합니다.
파일을 저장하고 Header 컴포넌트를 잘 렌더링하는지 확인합니다.
Header.js에서 Header 컴포넌트를 불러와 렌더링한 페이지
Header.js에서 Header 컴포넌트를 불러와 렌더링한 페이지
결과를 보면 Header 컴포넌트를 잘 렌더링하고 있습니다.
다음으로 페이지의 몸통 역할을 수행할 Body와 페이지 정보를 표시할 Footer 컴포넌트를 만들겠습니다. component 폴더에 Body.js와 Footer.js를 각각 만들고 다음과 같이 코드를 작성합니다.
코드를 불러오는 중 입니다 ...코드를 불러오는 중 입니다 ...
이제 component 폴더에는 Header.js, Body.js, Footer.js 3개의 파일이 존재해야 합니다.
BodyFooter를 페이지에 렌더링하려면 App.js에서 두 컴포넌트를 불러와 App의 자식으로 배치해야 합니다. App.js를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...
파일을 저장하고 페이지에서 Header, Body, Footer 컴포넌트를 잘 렌더링하는지 확인합니다.
Header, Body, Footer 컴포넌트를 페이지에서 렌더링하기
Header, Body, Footer 컴포넌트를 페이지에서 렌더링하기
3개의 컴포넌트를 잘 렌더링하고 있습니다.
 
NEXT2. JSX