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

3. 컴포넌트에 값 전달하기

리액트 앱을 만들다 보면 컴포넌트가 다른 컴포넌트에 값을 전달해야 하는 상황이 생깁니다. 이번 절에서는 컴포넌트 간에 값을 주고받는 방법을 알아보겠습니다.

Props란

리액트에서는 부모가 자식 컴포넌트에 단일 객체 형태로 값을 전달할 수 있습니다.이 객체를 리액트에서는 Props(Properties)라고 합니다. Props는 Properties의 줄임말로 속성이라는 뜻입니다.
Props 객체가 왜 이런 이름을 갖게 되었는지 이해하려면, 컴포넌트가 어떤 상황에서 자식에게 값을 전달하는지 알아야 합니다. 물론 Props라는 이름이 왜 붙었는지 몰라도 이 책의 실습 내용을 진행하는 데 문제는 없습니다. 따라서 만약 아래의 내용이 잘 이해되지 않는다면, 잠시 건너뛴 다음 실습을 마치고 다시 살펴볼 것을 권합니다.
리액트에서는 보통 재사용하려는 요소를 컴포넌트로 만듭니다. 예를 들어 게시 판 페이지를 리액트로 만든다고 가정해 봅시다. 사용자가 게시판에서 작성한 글은 게시물 리스트에서 하나의 항목으로 표시됩니다. 그런데 이 리스트에 존재하는 여러 게시물 항목은 내용은 각각 다르지만, 모두 동일한 구조입니다. 리액트에서는 내용은 다르지만 구조가 같은 요소를 주로 컴포넌트로 만듭니다. 여러 게시물 리스트를 페이지에 표시할 때는 이 컴포넌트를 반복해 렌더링하고, 게시물 각각의 내용은 Props로 전달합니다.
이해를 좀 더 돕기 위해 이 책의 최종 프로젝트인 [감정 일기장] 앱을 예로 들어보겠습니다. 다음은 사용자가 작성한 일기를 리스트 형태로 보여주는 페이지입니다
감정 일기장 프로젝트
감정 일기장 프로젝트
위 그림의 감정 일기장은 일기 리스트를 보여주는데, 각각의 일기 항목은 컴포넌트로 구성되어 있습니다. 이 각각의 컴포넌트를 일기 컴포넌트라고 하겠습니다. 현재 감정 일기장에는 일기 컴포넌트가 2개 있는 셈입니다.
2개의 일기 컴포넌트는 요소의 크기나 배열 등은 모두 같지만, 일기 내용, 작성일자, 감정 상태를 표현하는 이미지는 다릅니다. 이렇듯 리액트에서는 컴포넌트의 공통 기능이 아닌 세부 기능을 표현할 때 Props를 사용합니다.
다음 그림과 같이 App가 Props로 작성일, 일기내용, 감정 상태를 전달 하면, 일기 컴포넌트는 전달된 Props를 토대로 일기 리스트를 페이지에 렌더링합니다.
일기 항목의 세부 내용을 Props로 전달
일기 항목의 세부 내용을 Props로 전달
리액트의 컴포넌트와 Props를 샌드위치 제조에 비유한다면 샌드위치의 겉을 둘러싸고 있는 빵은 컴포넌트이고 샌드위치의 속은 Props와 같습니다. 다 똑같은 샌드위치지만 Props로 햄을 전달하면 햄 샌드위치가 되고, 야채를 넣으면 야채 샌드위치가 되는 원리와 흡사합니다.
보통 리액트에서 컴포넌트에 값을 전달하는 경우는 세부 사항들, 즉 컴포넌트의 속성을 지정하는 경우가 대부분입니다. 따라서 컴포넌트에 값을 전달하는 속성들 이라는 점에서 Properties라고 부르며, 이를 간단히 줄여 Props라고 합니다.

Props로 값 전달하기

그럼 컴포넌트에 Props를 전달하겠습니다. Body 컴포넌트에 변수 name을 Props로 전달합니다.
여기서 한 가지 주의할 사항이 있습니다. Props는 부모만이 자식 컴포넌트에 전달할 수 있습니다. 그 역은 성립하지 않습니다. 따라서 Body 컴포넌트에 Props를 전달하려면 부모인 App 컴포넌트에서 전달해야 합니다.

Props로 하나의 값 전달하기

App.js를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...
Props를 전달하려는 자식 컴포넌트 태그에서 이름={값} 형식으로 작성하면 됩니다.
전달하는 Props는 단일객체입니다. 따라서 객체 Props에는 name 프로 퍼티가 추가됩니다. 이 과정을 그림으로 표현하면 다음과 같습니다.
App 컴포넌트가 Body에 Props 전달
App 컴포넌트가 Body에 Props 전달
이번에는 App에서 전달한 Props를 Body 컴포넌트에서 사용하겠습니다.
Body.js에서 기존 내용을 모두 지우고 다음과 같이 작성합니다.
코드를 불러오는 중 입니다 ...
부모 컴포넌트에서 전달된 객체 Props는 함수의 매개변수 형태로 저장됩니다. 이 코드에서는 props라는 이름의 매개변수에 저장됩니다.  매개변수 props의 값을 확인하기 위해 개발자 도구의 콘솔에 출력합니다.  객체 props의 name 프로퍼티 값을 렌더링합니다.
전달된 Props에 어떤 값이 들어 있는지 콘솔에서 확인합니다.
그리고props.name 값을 페이지에서 잘 렌더링하는지도 확인합니다.
Props 사용하기
Props 사용하기
개발자 도구의 콘솔을 확인하면 App 컴포넌트에서 전달된 Props 값(name: "이정환")이 출력됩니다. 그리고 페이지에서도 props.name의 값 이정환을 잘 렌더링하고 있습니다.
✋🏼
개발자 도구의 콘솔에 나오는 Object 요소 왼쪽에 있는 삼각형(▶) 표시를 클릭하면 해당 객체의 name 값을 확인할 수 있습니다.

Props로 여러 개의 값 전달하기

이번에는 App에서 Body 컴포넌트에 객체 Props로 여러 개의 값을 담아 전달하겠습니다. 먼저 App 컴포넌트를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...
App에서 Body 컴포넌트에 Props로 2개의 값 name, location을 전달합니다. 변수를 미리 선언하지 않아도 location={"부천시"} 처럼 객체 Props에 프로퍼티를 추가해 전달 할 수 있습니다.
Props로 2개의 값 전달하기
Props로 2개의 값 전달하기
이번에는 Body 컴포넌트에서 Props로 전달된 2개의 값을 사용하겠습니다.
코드를 불러오는 중 입니다 ...
전달된 Props를 개발자 도구의 콘솔에 출력합니다.  Props로 전달된 name과 location을 페이지에 렌더링합니다.
Props가 제대로 전달되었는지 콘솔과 페이지에서 확인합니다.
Props로 전달한 2개의 값 확인하기
Props로 전달한 2개의 값 확인하기

구조 분해 할당으로 여러 개의 값 사용하기

Props로 전달된 값이 많으면, 이 값을 사용할 때마다 객체의 점 표기법을 사용해야 해서 여간 불편한게 아닙니다. 그런데 Props는 객체이므로 구조 분해 할당하면 간편하게 사용할 수 있습니다.
다음과 같이 Body 컴포넌트를 수정합니다.
코드를 불러오는 중 입니다 ...
매개변수 props에 있는 name, location 프로퍼티를 구조 분해 할당하여 같은 이름의 상수에 저장합니다.  name과 location의 값을 개발자 도구의 콘솔에 출력합니다.  props.name, props.location 대신 구조 분해 할당한 name, location 값을 페이지에 렌더링합 니다.
저장하고 결과를 콘솔과 페이지에서 확인합니다.
구조 분해 할당한 값 사용하기
구조 분해 할당한 값 사용하기
콘솔의 결과를 보면 결괏값은 객체가 아닌 상숫값임을 알 수 있습니다.
Body 컴포넌트의 매개변수에서 구조 분해 할당하면 더 간결한 코드를 작성할 수 있습니다.
코드를 불러오는 중 입니다 ...
매개변수에 전달된 Props 객체를 구조 분해 할당합니다.
이 코드의 결과는 앞의 코드와 동일합니다. 두 가지 방식 모두 큰 차이점은 없으나 실무에서는 매개변수에 구조 분해 할당하는 방식이 더 간결한 코드를 작성할 수 있어 선호하는 편입니다.

스프레드 연산자로 여러 개의 값 쉽게 전달하기

반대로 부모 컴포넌트에서 Props로 전달할 값이 많으면, 값을 일일이 명시해야 하므로 불편할 뿐만 아니라 가독성도 떨어집니다. 이때 Props로 값을 하나의 객체로 만든 다음, 스프레드 연산자를 활용해 전달하면 훨씬 간결하게 코드를 작성할 수 있습니다.
다음과 같이 App에서 Body 컴포넌트에 전달할 값을 객체로 만든 다음, 스프레드 연산자를 이용해 객체의 프로퍼티를 각각 Props 값으로 전달합니다.
코드를 불러오는 중 입니다 ...
Body 컴포넌트에 Props로 전달할 값을 객체 BodyProps로 만듭니다.  스프레드 연산자로 객체 BodyProps 각각의 프로퍼티를 Props 값으로 전달합니다.
스프레드 연산자를 활용하면 객쳇값을 Props로 쉽게 전달할 수 있습니다. 저장하고 결과를 확인합니다.
스프레드 연산자를 이용해 객체의 값으로 전달하기
스프레드 연산자를 이용해 객체의 값으로 전달하기

기본값 설정하기

App에서 Body 컴포넌트에 전달할 값을 하나 더 늘리겠습니다. 다음과 같이 App 컴포넌트를 수정합니다.
코드를 불러오는 중 입니다 ...
좋아하는 음식을 담은 배열 favorList를 객체 BodyProps에 추가합니다.
Body 컴포넌트에서 좋아하는 음식의 개수를 페이지에 렌더링하겠습니다.
Props로 전달된 배열 favorList의 요소 개수를 출력하면 됩니다. Body 컴포넌트를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...
Props에서 구조 분해 할당할 값에 배열 favorList를 추가합니다.  favorList를 포함한 Props의 값을 콘솔에 출력합니다.  배열 favorList에 포함된 요소의 개수를 출력합니다.
저장하고 콘솔과 페이지에서 결과를 확인하면 다음과 같습니다.
Props에 배열 favorList 추가하기
Props에 배열 favorList 추가하기
그런데 실수로 App 컴포넌트에서 Props의 값 중 favorList를 전달하지 않으면 어떻게 될까요? 다음과 같이 App 컴포넌트를 수정하겠습니다.
코드를 불러오는 중 입니다 ...
favorList를 실수로 전달하지 않았다는 상황을 가정하기 위해 주석 처리합니다.
저장하고 결과를 확인하면 오류가 발생합니다.
favorList를 실수로 전달하지 않아 오류 발생
favorList를 실수로 전달하지 않아 오류 발생
App에서 실수로 favorList를 전달하지 않으면, Body 컴포넌트의 배열 favorList의 값은 undefined가 됩니다. Body 컴포넌트에서는 favorList를 배열로 예상하고, 배열의 길이를 렌더링하기 위해 length 프로퍼티로 접근합니다.
따라서 undefined의 프로퍼티를 읽을 수 없다라는 메시지와 함께 오류가 발생합니다. 이런 경우를 대비해 defaultProps를 사용합니다. defaultProps를 이용하면 컴포넌트가 받을 Props의 기본값을 미리 설정할 수 있기 때문에 오류를 미연에 방지할 수 있습니다.
Body 컴포넌트에서 다음과 같이 작성합니다.
코드를 불러오는 중 입니다 ...
Body 컴포넌트가 받을 Props에서 favorList의 기본값을 빈 배열로 설정합니다.
저장하고 결과를 확인하면 App 컴포넌트에서 실수로 배열 favorList를 전달하지 않아도 오류가 발생하지 않습니다. Body 컴포넌트에서 favorList의 기본값을 빈 배열로 설정해 두었기 때문입니다.
실무에서는 백엔드 서버에서 Props로 데이터를 주고받는 경우가 많습니다. 이때 예상치 못한 서버 오류로 인해 정상적인 값을 받지 못하면 오류가 발생합니다. defaultProps를 이용하면 효율적으로 이런 오류를 방지할 수 있습니다
defaultProps로 Props의 기본값 설정하기
defaultProps로 Props의 기본값 설정하기

Props로 컴포넌트 전달하기

지금까지 컴포넌트 간에 Props로 문자열이나 숫자 같은 자바스크립트 값을 전달해 보았습니다. 그런데 Props로는 자바스크립트 값뿐만 아니라 컴포넌트도 전달할 수 있습니다.
이번에는 App에서 Body로 컴포넌트를 하나 전달하겠습니다. App.js를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...
새로운 컴포넌트 ChildComp를 만듭니다.  ChildComp를 Body 컴포넌트의 자식 요소로 배치합니다.
Body 컴포넌트의 자식 요소로 ChildComp를 배치했습니다. 리액트에서는 자식 컴포넌트에 또 다른 컴포넌트를 배치하면, 배치된 컴포넌트는 자동으로 Props의 children 프로퍼티에 저장되어 전달됩니다.
children 프로퍼티에 저장된 자식 컴포넌트를 사용하겠습니다. Body 컴포넌트를 다음과 같이 수정합니다.
코드를 불러오는 중 입니다 ...
App에서 Body 컴포넌트의 자식으로 배치한 ChildComp는 children 프로퍼티로 전달되어 매개 변수 children에 저장됩니다.  children을 콘솔에 출력합니다. children을 자바스크립트 표현식을 사용하듯 렌더링합니다.
Props의 children 프로퍼티로 전달되는 자식 컴포넌트는 값으로 취급하므로 JSX의 자바스크립트 표현식으로 사용할 수 있습니다. children에는 컴포넌트 ChildComp가 저장되어 있기 때문에 해당 컴포넌트를 렌더링합니다.
저장하고 결과를 콘솔과 페이지에서 확인합니다.
children에 저장된 컴포넌트 렌더링
children에 저장된 컴포넌트 렌더링
컴포넌트를 개발자 도구의 콘솔에서 출력하면 객체 형식의 값을 출력합니다. 앞서 JSX에서는 자바스크립트 표현식이 객체를 평가할 경우 오류가 발생한다고 했지만, 이 객체는 리액트 컴포넌트를 표현한 것이므로 오류가 발생하지 않습니다.
 
PREV2. JSX
NEXT4. 이벤트 처리하기