컴포넌트(Component)
컴포넌트(component)란 프로그래밍에서 재활용 가능한 독립적인 모듈을 의미합니다.
리액트나 뷰(Vue.js)와 같은 프론트엔트에서 컴포넌트는
앱의 화면을 구성하는 가장 기본적인 단위입니다.
컴포넌트는 독립적이고 덜 의존적이기 때문에 한번 호출해서 사용하는 걸로 끝나는 것이 아니라
여러번에 걸쳐 재사용될 수 있습니다.
리액트 컴포넌트는
아래 코드와 같이 JSX 코드로 작성한 리액트 요소(element)를 반환하는 함수식으로 작성됩니다.
컴포넌트를 정의할때 함수명은 보통 맨 앞자마다 대문자로 표기하는
파스칼케이스(PascalCase)로 작성합니다.
리액트 함수형 컴포넌트는 반드시 리액트 Element를 return해야 합니다.
const BoxComponent = () => {
return (
<ul>
<li>컴포넌트</li>
<li>props</li>
<ul/>
);
};
한 번 정의된 컴포넌트는
JSX식 내에서 꺽쇄 기호<>를 사용한 태그 형태로 사용할 수 있습니다.
BoxComponent가 반환하는 리액트 element가 <div> 태그 안에 담기게 됩니다.
const ContainerComponent = () => {
return (
<div>
<BoxComponent />
</div>
);
};
화면 구성을 컴포넌트 단위로
리액트의 화면 UI는 컴포넌트의 조합으로 구성됩니다.
하나의 최상위 컴포넌트가 하위의 모든 컴포넌트를 포함하는 구조를 띄고 있습니다.
전체 화면에서 부분마다 컴포넌트 단위로 잘 나누어 설계하는 것이 중요합니다.
중복되는 요소는 최대한 줄이면서 모든 컴포넌트가 독립적인 목적을 가지고 있어야 합니다.
컴포넌트(Component) / Props 속성
위 이미지에서 파란색 테두리의 Main 화면 영역은
사용자가 상품을 구매하는 Shop 화면이라 가정하겠습니다.
이 화면을 리액트 컴포넌트로 개발한다고 생각해 봅시다.
<Product /> 컴포넌트가 각 상품의 이미지와 정보를 보여주는 상품 컴포넌트가 될 것이고
<Main /> 컴포넌트가 상품 컴포넌트들을 모두 포함해서 보여주는 컨테이너 컴포넌트
관련 리액트 코드는 간단하게 아래처럼 작성할 수 있을 겁니다.
이때 <Product /> 컴포넌트는
자신이 어떤 상품 정보를 보여줄지에 대한 상품 정보를 각각 배정 받아야 합니다.
그렇지 않고 위 코드처럼 <Product />가 상품 정보를 내부에 자체적으로 가지고 있다면
모든 <Product />는 같은 이미지, 같은 설명만 보여줄 것입니다.
이때 props 를 활용하면
각각의 상품 데이터를 상위 컴포넌트에서 하위 컴포넌트에게 지정해서 내려줄 수 있습니다.
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/>
);
};
함수형 컴포넌트에서 첫번째 인자는 무조건 props 객체입니다.
props 객체에 전달 받은 데이터들이 포함되어 있습니다.
<Product />에서 함수의 첫 번째 인자를 props로 선언하고
이미지 경로와 이름도 자바스크립트 표현식을 통해
props의 값을 사용하는 것으로 수정하겠습니다.
// ▶ Product 컴포넌트
const Product = (props) => {
return (
<div>
<img src={props.image}>
<p>{props.name}</p>
</div>
);
};
➕ props 객체에 구조분해할당을 적용해서 사용하면 보다 편리합니다.
함수형 컴포넌트에서 첫번째 인자에 객체 구조분해할당을 적용해서 props를 사용하는 것이 일반적인 방법입니다.
// ▶ Product 컴포넌트
const Product = ({ image, name }) => {
return (
<div>
<img src={image}>
<p>{name}</p>
</div>
);
};
⛔ props는 읽기 전용으로만 사용해야 합니다.
props는 읽기 전용으로만 사용하고 값을 직접 변경하는 경우는 없어야 합니다.
아래 코드처럼 작성하는 경우는 없어야 합니다.
이미 랜더링된 컴포넌트에서 props의 값을 직접 변경하게 되는 경우 화면에 변경된 값이 적용되지 않습니다.
🔎 컴포넌트에서 어떠한 조건에 따라 데이터 변경이 발생하는 경우,
props값이 아닌 상태(state)를 사용해 값을 변경해야 합니다.
// ▶ Product 컴포넌트
const Product = ({ image, name }) => {
// 클릭 했을때 name에 구매하기 텍스트를 추가하는 함수
const nameChange = () => {
name = `${name} 구매하기`;
}
return (
<div>
<img src={image}>
<p onClick={nameChange}>{name}</p>
{/* 클릭해서 함수가 실행되더라도 화면에 변경된 name이 적용되지 않음 */}
</div>
);
};
map() 함수를 사용한 컴포넌트 반복 생성
map() 함수가 products 배열을 순회하면서 <Products /> 컴포넌트를 동적으로 생성합니다.
JSX 문법을 공부하셨다면, 이전 <Main /> 컴포넌트의 코드를 개선하는 방법이 있다는 것을 아실겁니다.
JSX식 내에서 자바스크립트 함수를 사용할 수 있으므로,
배열의 map() 함수를 활용하면 컴포넌트를 동적으로 생성할 수 있습니다.
한 가지 주의할 점은 map() 함수와 같은 iterator를 사용해서 컴포넌트를 반복 생성할 경우
컴포넌트마다 고유한 key 값을 지정해줘야 합니다.
필수는 아니지만 key 값이 없을 경우 경고를 표시합니다.
리액트에서 반복 생성된 컴포넌트를 구별하기 위해 필요한 값이므로 지정해주는 것을 원칙으로 합시다.
별다른 고유한 값이 없다면 위 코드처럼 각 배열 아이템의 index를 지정해 주면 됩니다.
// ▶ 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/>
);
};
출처 : https://www.jinlog.org/9654c998-f8aa-4a9e-b7b0-33577999b0c7
'📌 Front End > └ React' 카테고리의 다른 글
[React] 리액트 사용자 정의 함수형 컴포넌트(Functional Component) - 클래스와 객체 인스턴스를 사용해 데이터 관리 (0) | 2024.08.18 |
---|---|
[React] React Vite TypeScript 개발환경 세팅하기 (Vite 설정 파일 - root: "./" 변경) (0) | 2024.08.17 |
[React] 리액트 JSX(TSX) 문법 (3) | 2024.08.17 |
[React] React Vite TypeScript 개발환경 세팅하기 (0) | 2024.08.14 |
[React] Vite 를 이용한 React + Typescript 실행환경 세팅하기 (0) | 2024.08.14 |