앞서 React란 무엇인지 다뤘다.
굳이 React를 사용하지 않아도 어떤 웹사이트라도 구축할 수 있지만 더 복잡한 interface를 지닌 것을 구축할 때 React 같은 framework를 사용한다면 작업이 훨씬 수월해질 것이다.
사소한 문제들에 신경쓸 필요가 없으며, 오류도 덜 발생할 것이다.
그저 응용프로그램을 구성하고 핵심 비지니스 로직을 작성하는 것에 집중할 수 있을 것이다.
그것이 React와 같은 library를 사용하는 이유가 될 것이다.
What is component?
React는 작업을 단순하게, 간단하게 만들기 위해 component라는 개념을 받아들였다.
흔히 component가 React의 전부라고 말한다.
그렇다면 component가 무엇인지 알기 전에 왜 전부라고 말하는지 알아야 할 것이다.
그 이유는 모든 사용자 interface들은 결국 component로 구성되어 있기 때문이다.
아래 예시를 보자 :)
해상 웹 페이지는 강의를 수강하면서 제작해야할 화면이다.
가격을 나타내는 블록을 자세히 보면 반복되는 아이템이 보일 것이다.
각각의 아이템들은 같은 아이템이지만 데이터가 다른 것을 볼 수 있다.
이런 아이템들을 component라고 하며 사용자 interface에서 재사용할 수 있는 building block이다.
다시 말해, 스타일을 만드는 HTML 코드와 CSS 코드 그리고 어떤 로직을 위한 JavaScript의 결합이다.
component를 만들기 위해서 반드시 component를 재사용할 필요는 없으며, 여기서 재사용 가능하다는 것은 component의 특징 중 하나일 뿐이다.
크게는 여러 카드들로, 작게는 글자나 날짜와 같은 아주 작은 단위로까지 나눌 수 있다.
이런 각각의 작은 buliding block들을 결합하여 사용자 interface를 구성하는 것이다.
React는 이런 component에 관한 모든 것이다.
최종적으로 사용자 interface를 어떻게 구성할 것인가를 명령하는 것이다.
그러면 React는 이렇게 작게 분할된 코드들을 합쳐서 하나의 페이지로 해석한다.
그렇게해서 사용자 interface를 구축한다.
Component의 특징
- 재사용 가능하다(Reusablilty)
- 반복적으로 작성해야하는 코딩들을 피할 수 있게 해준다.
- 관심사들을 분리할 수 있다(Separation of Concerns)
- 코드들을 작게 분할하여 관리 가능한 단위로 유지할 수 있게 해준다.
- 모든 코드들을 커다란 하나의 파일로 저장하는 것이 아니라 특정한 목적에 맞게, 하나로 명확하게 초점을 맞춰 집중할 수 있다.
Component의 구성
결국 사용자 interface는 HTML, CSS, JavaScript에 관한 것으로 React로 작업할 때 component를 구축해서 제작된다.
Declarative Approach(선언형 접근방식)을 통해 programming할 수 있다.
다시 말해, 원하는 대상 상태를 정의하고 React가 실제 JavaScript Dom 지시사항을 파악하도록 코드를 짠다는 말이다.
이해를 돕고자 위의 코드를 통해 React에서 component를 어떤 방식으로 작성하는지 볼 수 있다.
8번 줄을 추가하고 싶다면 일반적인 JavaScript의 경우, 2-4번 줄의 형식으로 추가를 해주어야한다.
그러나 React는 declarative approach를 택하고 있어서 복잡하거나 번거로운 작업 대신에 간단한 지시사항으로 뒷단에서 생성할 것이다.
Component의 구조
JavaScript Dom에 마운트되는 루트 component <App />에서 여러 일들은 하위에 작은 component들로 나뉘는 tree 구조를 띈다.
Component 작명 방법
보통의 작명은 원하는대로 가능하지만, component 작명은 관례로 몇 가지 존재한다.
- PascalCase(Upper Camel Case)로 작명한다.
- 첫 글자는 대문자로 시작해야한다.
- 단어와 단어가 결합한 경우, 서브 단어의 첫 글자를 대문자로 시작해야한다.
- 직관적인 예시 : PhoneNumber, CreatedAt, UpdatedAt
- 직관적으로 어떤 기능을 하는 component인지 알 수 있도록 기능에 관하여 작명한다.
React에서는 소문자로 시작하는 tag들(div, h1, p ...)은 내장된 HTML 요소이기 때문에 내장 요소로 찾을 것이며, 대문자로 시작하는 tag들은 개발자들에게 의해 정의된 요소로 사용자 지정 component라는 것을 알아차릴 것이다.
JSX 코드 작성
기본적으로 component는 JavaScript 파일에서 작성된다.
하지만 JavaScript에서 component를 작성하려면 imperative approch(명령형 접근방식)으로 작성해야한다.
그렇기에 React 팀에서 해당 문제를 해결하기 위해 JSX를 도입했다.
JSX에 관한 설명은 아래 글을 참고해주길 바란다.
CSS 사용하기
component에서 사용되는 여러 요소들에 스타일을 적용하기 위해서는 CSS가 필요하다.
.js
파일에서 CSS파일을 불러오는 방법은 아래와 같다: )
import './Path/someStyle.css'
module에서 다뤘던 파일 불러오기 방식이랑은 차이가 있어보인다.
React에서 CSS 파일을 불러오기 위해서 해당 문법을 사용하도록 지시하고 있기 때문이다.
그렇다면, 어떻게 JSX 문법에 맞춰서 스타일을 적용할까?
import './ExpenseItem.css' ;
function ExpenseItem() {
return (
// <div class="expense-item"> Not class, use className attribute
<div className="expense-item">
<div>Data</div>
<div className="expense-item__description">
<h2>Title</h2>
<div className="expense-item__price">Amount</div>
</div>
</div>
);
}
export default ExpenseItem;
CSS 파일에서 제작한 class를 적용하는 방식이다.
조금 이상해보이더라도 이 방법을 기억해야한다. 여기서 적용되는 HTML은 진정한 HTML이 아니라 React 팀에서 만든 JSX 구문이기 때문에 결국엔 여전히 JavaScript이다. JavaScript에는 class가 이미 예약어로 존재하기 때문에 class style을 적용하고 싶다면 위의 방식을 따라야한다.
그럼 id style도 다른 방식이냐 물어볼 수도 있다. id는 기존의 id = ""
attribute로 사용해도 무관하다.
props 사용하기
component를 제작하여 특정 값들을 띄워주고 싶다. 하지만 그 값이 동적으로 변할 수 있는 값이었으면 하는데, 그렇지 않으면 component를 재사용하여도 언제나 같은 값을 보여줄 것이기 때문에 재사용하는 의미가 없어져버린다. 해당 데이터가 component에 고정되어 있기 때문이다.
우리가 함수를 사용할 때, 여러번 호출하지만 매번 다른 기능을 하게 사용할 수 있는 것은 parameter(매개변수) 값을 다르게 주어 다른 값을 출력하도록 만드는 것에 있다. React는 이러한 함수와 동일한 개념이 내장되어 있기 때문에 재사용할 수 있는 component를 만들 수 있다. 그것이 바로 props이다.
props는 properties를 나타낸 것으로, 사용자 지정 component의 속성을 설정할 수 있다. 마치 HTML tag의 attribute를 사용하는 것처럼 사용할 수 있다.
상위 component에서 하위 component로 값을 인자로 전달하고 싶을 때 props를 쓴다.
Top-Down approach(하향식 접근 방식)으로 component간의 communication을 진행할 수 있다.
// 📂 App.js
import ExpenseItem from "./components/ExpenseItem";
function App() {
const expenses = [
{
id: "e1",
title: "Toilet Paper",
amount: 94.12,
date: new Date(2020, 7, 14),
},
{ id: "e2", title: "New TV", amount: 799.49, date: new Date(2021, 2, 12) },
{
id: "e3",
title: "Car Insurance",
amount: 294.67,
date: new Date(2021, 2, 28),
},
{
id: "e4",
title: "New Desk (Wooden)",
amount: 450,
date: new Date(2021, 5, 12),
},
];
return (
<div>
<h2>Let's get started!</h2>
<ExpenseItem
title={expenses[0].title}
amount={expenses[0].amount}
date={expenses[0].date}
></ExpenseItem>
<ExpenseItem
title={expenses[1].title}
amount={expenses[1].amount}
date={expenses[1].date}
></ExpenseItem>
<ExpenseItem
title={expenses[2].title}
amount={expenses[2].amount}
date={expenses[2].date}
></ExpenseItem>
<ExpenseItem
title={expenses[3].title}
amount={expenses[3].amount}
date={expenses[3].date}
></ExpenseItem>
</div>
);
}
export default App;
// 📂 ExpenseItem.js
import "./ExpenseItem.css";
function ExpenseItem(props) {
return (
<div className="expense-item">
<div>{props.date.toISOString()}</div>
<div className="expense-item__description">
<h2>{props.title}</h2>
<div className="expense-item__price">${props.amount}</div>
</div>
</div>
);
}
export default ExpenseItem;
상위 component에서 여러 속성으로 값을 전달하게 되면 하위 component에서는 객체 형식으로 받게된다. 모든 component는 하나의 parameter만 받을 수 있기 때문이다. 이 때에 전달받은 props의 key값은 상위 component에서 사용한 속성이름을 사용한다.
이런 식으로 같은 component를 다른 값으로 재사용할 수 있게 되었다.