Search

컴포넌트(component)와 props

컴포넌트(component)란 프로그래밍에서 재활용 가능한 독립적인 모듈을 의미합니다. 리액트나 뷰(Vue.js)와 같은 프론트엔트에서 컴포넌트는 앱의 화면을 구성하는 가장 기본적인 단위입니다. 컴포넌트는 독립적이고 덜 의존적이기 때문에 한번 호출해서 사용하는 걸로 끝나는 것이 아니라 여러번에 걸쳐 재사용될 수 있습니다.
리액트 컴포넌트는 아래 코드와 같이 JSX 코드로 작성한 리액트 요소(element)를 반환하는 함수식으로 작성됩니다. 컴포넌트를 정의할때 함수명은 보통 맨 앞자마다 대문자로 표기하는 파스칼케이스(PascalCase)로 작성합니다.
const BoxComponent = () => { return ( <ul> <li>컴포넌트</li> <li>props</li> <ul/> ); };
JavaScript
복사
리액트 함수형 컴포넌트는 반드시 리액트 Element를 return해야 합니다.
한번 정의된 컴포넌트는 JSX식 내에서 꺽쇄 기호<>를 사용한 태그 형태로 사용할 수 있습니다.
const ContainerComponent = () => { return ( <div> <BoxComponent /> </div> ); };
JavaScript
복사
BoxComponent가 반환하는 리액트 element가 <div> 태그 안에 담기게 됩니다.

화면 구성을 컴포넌트 단위로

리액트의 화면 UI는 컴포넌트의 조합으로 구성됩니다. 하나의 최상위 컴포넌트가 하위의 모든 컴포넌트를 포함하는 구조를 띄고 있습니다. 전체 화면에서 부분마다 컴포넌트 단위로 잘 나누어 설계하는 것이 중요합니다. 중복되는 요소는 최대한 줄이면서 모든 컴포넌트가 독립적인 목적을 가지고 있어야 합니다.
화면 요소가 중복되는 경우 NavItem이나 Product처럼 컴포넌트를 재사용 할 수 있도록 만들어야 합니다.

컴포넌트와 props

위 이미지에서 파란색 테두리의 Main 화면 영역은 사용자가 상품을 구매하는 Shop 화면이라 가정하겠습니다. 이 화면을 리액트 컴포넌트로 개발한다고 생각해 봅시다. <Product /> 컴포넌트가 각 상품의 이미지와 정보를 보여주는 상품 컴포넌트가 될 것이고 <Main /> 컴포넌트가 상품 컴포넌트들을 모두 포함해서 보여주는 컨테이너 컴포넌트가 될 것입니다. 관련 리액트 코드는 간단하게 아래처럼 작성할 수 있을 겁니다.
컴포넌트를 이해하기 위해 예시로 작성하는 것이므로 스타일 관련 코드는 생략하겠습니다.
// Product 컴포넌트 const Product = () => { return ( <div> <img src="image.png"> <p>상품 이름</p> </div> ); };
JavaScript
복사
// Main 컴포넌트 const Main = () => { return ( <div> <Product /> <Product /> <Product /> <div/> ); };
JavaScript
복사
이때 <Product /> 컴포넌트는 자신이 어떤 상품 정보를 보여줄지에 대한 상품 정보를 각각 배정 받아야 합니다. 그렇지 않고 위 코드처럼 <Product />가 상품 정보를 내부에 자체적으로 가지고 있다면 모든 <Product />는 같은 이미지, 같은 설명만 보여줄 것입니다. 이때 props 를 활용하면 각각의 상품 데이터를 상위 컴포넌트에서 하위 컴포넌트에게 지정해서 내려줄 수 있습니다.
상위 컴포넌트에서 받은 props를 통해 같은 Product 컴포넌트라도 개별 상품 정보를 보여줄 수 있습니다.
props는 리액트 컴포넌트의 프로퍼티(properties)입니다. 리액트 컴포넌트는 props를 사용할때 순수 함수처럼 동작하기 때문에 컴포넌트의 인자(arguments) 개념으로 생각할 수도 있습니다.
상위 컴포넌트에서 하위 컴포넌트에게 전달할 props를 정의하는 것은 HTML에서 태그 속성(attribute)을 정의하는 것과 같습니다. 태그 내부에 key=value 형태로 작성하면 됩니다.
상위 컴포넌트인 <Main />에서 <Product />props를 각각 지정해 주겠습니다.
// Main 컴포넌트 const Main = () => { return ( <div> <Product image="/apple.png" name="사과" /> <Product image="/banana.png" name="바나나" /> <Product image="/strawberry.png" name="딸기" /> <div/> ); };
JavaScript
복사
함수형 컴포넌트에서 첫번째 인자는 무조건 props 객체입니다. props 객체에 전달 받은 데이터들이 포함되어 있습니다.
<Product />에서 함수의 첫번째 인자를 props로 선언하고 이미지 경로와 이름도 자바스크립트 표현식을 통해 props의 값을 사용하는 것으로 수정하겠습니다.
// Product 컴포넌트 const Product = (props) => { return ( <div> <img src={props.image}> <p>{props.name}</p> </div> ); };
JavaScript
복사
props 객체에 구조분해할당을 적용해서 사용하면 보다 편리합니다.
// Product 컴포넌트 const Product = ({ image, name }) => { return ( <div> <img src={image}> <p>{name}</p> </div> ); };
JavaScript
복사
함수형 컴포넌트에서 첫번째 인자에 객체 구조분해할당을 적용해서 props를 사용하는 것이 일반적인 방법입니다.
props읽기 전용으로만 사용해야 합니다. 아래 코드처럼 작성하는 경우는 없어야 합니다. 이미 랜더링된 컴포넌트에서 props의 값을 직접 변경하게 되는 경우 화면에 변경된 값이 적용되지 않습니다.
// Product 컴포넌트 const Product = ({ image, name }) => { // 클릭 했을때 name에 구매하기 텍스트를 추가하는 함수 const nameChange = () => { name = `${name} 구매하기`; } return ( <div> <img src={image}> <p onClick={nameChange}>{name}</p> {/* 클릭해서 함수가 실행되더라도 화면에 변경된 name이 적용되지 않음 */} </div> ); };
JavaScript
복사
 props는 읽기 전용으로만 사용하고 값을 직접 변경하는 경우는 없어야 합니다.
컴포넌트에서 어떠한 조건에 따라 데이터 변경이 발생하는 경우, props값이 아닌 상태(state)를 사용해 값을 변경해야 합니다. 리액트의 상태(state)에 대한 설명은 다음 포스트 상태(state) 관리 에서 확인하세요.

map() 함수를 사용한 컴포넌트 반복 생성

JSX 문법을 공부하셨다면, 이전 <Main /> 컴포넌트의 코드를 개선하는 방법이 있다는 것을 아실겁니다. JSX식 내에서 자바스크립트 함수를 사용할 수 있으므로, 배열의 map() 함수를 활용하면 컴포넌트를 동적으로 생성할 수 있습니다.
// props로 내려주던 각각의 데이터를 객체로 만들고 products 배열에 포함 const products = [ { image: '/apple.png', name: '사과', }, { image: '/banana.png', name: '바나나', }, { image: '/strawberry.png', name: '딸기', }, ]; // Main 컴포넌트 const Main = () => { return ( <div> { /* JSX식 내에서 호출된 함수는 실행된 결과를 랜더링 */ products.map((item, index) => ( <Product key={index} image={item.image} name={item.name} /> )) } <div/> ); };
JavaScript
복사
map() 함수가 products 배열을 순회하면서 <Products /> 컴포넌트를 동적으로 생성합니다.
한가지 주의할 점은 map() 함수와 같은 iterator를 사용해서 컴포넌트를 반복 생성할 경우 컴포넌트마다 고유한 key 값을 지정해줘야 합니다. 필수는 아니지만 key 값이 없을 경우 경고를 표시합니다. 리액트에서 반복 생성된 컴포넌트를 구별하기 위해 필요한 값이므로 지정해주는 것을 원칙으로 합시다. 별다른 고유한 값이 없다면 위 코드처럼 각 배열 아이템의 index를 지정해 주면 됩니다.

 JSX 문법

 상태(state) 관리

React 시작하기 목록