본문 바로가기

Study/React

Component & Props

how to make Component? 

1. structure

// components/ExpenseItem.js
function ExpenseItem() {
  return <h2>expense item!</h2>;
}

export default ExpenseItem;

// app.js
import ExpenseItem from './components/ExpenseItem';

function App() {
  return (
    <div>
      <ExpenseItem />
    </div>
  );
}

export default App;

 

  1. src/ components |  이 폴더 안에서 각 컴포넌트 별로 파일을 만들어서 작업한다.
    • 이 때 App 컴포넌트는 일반적인 UI와는 다른 root 컴포넌트이기 때문에, components 폴더 안으로 이동시키지 않는다. 
  2. 컴포넌트의 파일명 |  대문자로 시작하며, Camel 표기법을 따른다. 파일의 확장자로는 js 또는 jsx를 사용할 수 있다. 
    • App.js에서 알 수 있듯이 리액트의 컴포넌트란, 함수이다. 
    • 즉 컴포넌트 파일 안에는, 컴포넌트를 반환하는 함수를 작성한다. 
    • 컴포넌트의 return 값은 브라우저에 렌더링할 목표 상태(target state)를 정의하는 방식으로 작성되고, 이러한 방식을 declarative approach라고 한다. 
  3. 컴포넌트를 App.js에 import 함으로써 브라우저에 렌더링할 수 있다. 
    • 컴포넌트 함수의 첫글자는 반드시 대문자로 작성해야하는데, 리액트가 이 대문자로 cumtom html element 인지, 아닌지를 판단하기 때문이다. 
    • 컴포넌트 함수가 반환하는 jsx 코드는 여러 개의 형제 요소를 반환할 수 없다(하나의 root elemet 만을 반환한다). 

2. adding styles

// ExpenseItem.js
import './ExpenseItem.css';

function ExpenseItem() {
  return (
    <div className='expense-item'>
      <strong className='date'>March 28th 2021</strong>
      <div className='description'>
        <h2>Car Insurance</h2>
        <p className='price'>$295.67</p>
      </div>
    </div>
  );
}

export default ExpenseItem;

 

  1. jsx 코드의 html 요소에 class를 지정할 때에는 className이라는 속성을 사용해야 한다. 
  2. 컴포넌트와 동일한 이름을 가진 css 파일을 만든다. 
  3. css 파일을 해당 컴포넌트 파일에 import 한다. 

3. dynamic data | props

what is props?

function ExpenseItem() {
  const expenseDate = new Date(2022, 5, 15);
  const expenseTitle = 'Car Insurance';
  const expenseAmount = 295.67;

  return (
    <section className='expense-item'>
      <strong className='date'>{expenseDate.toDateString()}</strong>
      <div className='description'>
        <h2>{expenseTitle}</h2>
        <p className='price'>${expenseAmount}</p>
      </div>
    </section>
  );
}

// app.js 
function App() {
  return (
    <div>
      <ExpenseItem />
      <ExpenseItem />
      <ExpenseItem />
    </div>
  );
}

 

  1. curly braces in jsx |  {culry braces}를 사용하면, 그 안에서 js expression code를 실행할 수 있다. 
  2. re-usability
    • app.js에서 <ExpenseItem /> 컴포넌트를 원하는 만큼 재사용할 수 있지만, 이것이 진정한 의미의 재사용이라고 보기는 어렵다.
    • 컴포넌트 내부에 데이터가 고정되어 있어서, 모든 컴포넌트가 같은 데이터를 보여주기 때문이다. 
  3. props | properties, 컴포넌트 외부에서 데이터를 전달하면, 전달받은 데이터에 맞게 UI를 렌더링할 수 있다. 
    • props은 컴포넌트 함수의 input과도 같다.
    • 함수가 input에 따라 다른 output을 반환하는 것처럼, 컴포넌트 함수에 data, 즉 props을 전달함으로써 컴포넌트를 재사용한다. 

how to use props?

1. 부모 컴포넌트 => 자식 컴포넌트

// app.js 
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) },
  ];

  return (
    <div>
      <ExpenseItem title={expenses[0].title} amount={expenses[0].amount} date={expenses[0].date}/>
      <ExpenseItem title={expenses[1].title} amount={expenses[1].amount} date={expenses[1].date}/>
      <ExpenseItem title={expenses[2].title} amount={expenses[2].amount} date={expenses[2].date}/>
    </div>
  );
}
// ExpenseItem.js
function ExpenseItem(props) {
  return (
    <section className='expense-item'>
      <strong className='date'>{props.date.toDateString()}</strong>
      <div className='description'>
        <h2>{props.title}</h2>
        <p className='price'>${props.amount}</p>
      </div>
    </section>
  );
}

 

  1. 각 컴포넌트에 데이터를 전달할 때, html의 property를 설정하는 것처럼 사용하기 때문에 props라는 이름이 붙었다. 
  2. 리액트가 컴포넌트에 전달된 properties를 하나의 객체에 담아 컴포넌트 함수의 첫번째 매개변수로 전달한다. 
  3. 각 컴포넌트는 이제 같은 UI를 가지고 있으면서도, 서로 다른 데이터를 보여줄 수 있다. 

2. 자식 컴포넌트 => 부모 컴포넌트

// NewExpense.jsx(부모)
const NewExpense = (props) => {
 const savaDataHandler = (data) => {
   return {...data, id: Math.random().toString + Math.random().toString}
 };
 
  return (
    <section className='container new-expense'>
      <h1 className='sr-only'>make new expense log</h1>
      <NewExpenseForm onSaveData={saveDataHandler} />
    </section>
  );
};

 

// NewExpenseForm.jsx(자식)
const NewExpenseForm = (props) => {
  // ... 
  const submitHandler = (e) => {
    e.preventDefault();

    const newExpenseData = {
      title: titleInput,
      amount: amountInput,
      date: new Date(dateInput),
    };
    
    props.saveDataHandler(newExpenseData); 
    
    setTitleInput('');
    setDateInput('');
    setAmountInput('');
  };
  // ...
}

 

  1. 부모 컴포넌트에서 자식 컴포넌트의 props에 데이터를 저장하는 함수를 전달한다.
  2. 자식 컴포넌트에서 해당 함수에 데이터를 인자로 전달해서 실행한다. 

what is Composition? | props.children

composition(합성)이란, 컴포넌트 안에 다른 컴포넌트가 포함되어 있는 것을 말한다. 어플리케이션의 규모가 커짐에 따라 UI가 복잡해지기 때문에 composition이 일어나는 것은 당연하다. wrapper component(container)도 이런 composition의 하나로 볼 수 있다.

 

+) modal이나 경고창은 대표적인 wrapper component이다. 이런 컴포넌트의 스타일링을 미리 지정해 놓으면 css 코드의 중복을 피할 수 있다. 

 

// Card.js
import './Card.css'; // Card에 공통적으로 적용할 스타일을 작성한다
function Card(props) {
  // 여기에서 card는 항상 적용할 default class이다(띄어쓰기). 
  const classes = 'card ' + props.className; 
  return (
    <div className={classes}>{props.children}</div>
  )
}

export default Card; 

// Item.js
function Item(props) {
  return (
    <Card className='card item'>
        <h1>{props.title}</h1>
        <p className='price'>${props.contents}</p>
    </Card>
  );
}

export default Item;

 

  1. props.children
    1. 일반적으로 cumstom tag는 자식 요소를 가질 수 없다. 
    2. props.childeren는 해당 컴포넌트의 자식 요소를 가리킨다.  
  2. props.className
    1. 일반적으로 cumstom tag는 className과 같은 속성을 가질 수 없다.
    2. 사용하고 싶은 속성이 있다면, 그 속성을 코드로 명시해야 한다. 

+) 컴포넌트에서 fontAwesome 이용하기 

$ yarn add @fortawesome/fontawesome-free
// index.js

import '@fortawesome/fontawesome-free/js/all.js';

 

index.js에 fontawesome을 import한 이유는, 아이콘이 사용되는 모든 모듈에서 import를 하는 것보다, index.js 한 곳에 import 해 두는 것이 간단하고 빠르게 아이콘을 출력할 수 있기 때문이다. 

'Study > React' 카테고리의 다른 글

Event & useState  (0) 2022.06.16
JSX  (0) 2022.06.16
What is React?  (0) 2022.06.16
MVC & Dependency Injection  (0) 2022.04.29
PostCSS  (0) 2022.04.23